// 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 template interface {
	expand(*strings.Builder, Values) error
	regexp(*strings.Builder)
}

type literals string

func ( literals) ( *strings.Builder,  Values) error {
	.WriteString(string())
	return nil
}

func ( literals) ( *strings.Builder) {
	.WriteString("(?:")
	.WriteString(regexp.QuoteMeta(string()))
	.WriteByte(')')
}

type varspec struct {
	name    string
	maxlen  int
	explode bool
}

type expression struct {
	vars   []varspec
	op     parseOp
	first  string
	sep    string
	named  bool
	ifemp  string
	escape escapeFunc
	allow  runeClass
}

func ( *expression) () {
	switch .op {
	case parseOpSimple:
		.sep = ","
		.escape = escapeExceptU
		.allow = runeClassU
	case parseOpPlus:
		.sep = ","
		.escape = escapeExceptUR
		.allow = runeClassUR
	case parseOpCrosshatch:
		.first = "#"
		.sep = ","
		.escape = escapeExceptUR
		.allow = runeClassUR
	case parseOpDot:
		.first = "."
		.sep = "."
		.escape = escapeExceptU
		.allow = runeClassU
	case parseOpSlash:
		.first = "/"
		.sep = "/"
		.escape = escapeExceptU
		.allow = runeClassU
	case parseOpSemicolon:
		.first = ";"
		.sep = ";"
		.named = true
		.escape = escapeExceptU
		.allow = runeClassU
	case parseOpQuestion:
		.first = "?"
		.sep = "&"
		.named = true
		.ifemp = "="
		.escape = escapeExceptU
		.allow = runeClassU
	case parseOpAmpersand:
		.first = "&"
		.sep = "&"
		.named = true
		.ifemp = "="
		.escape = escapeExceptU
		.allow = runeClassU
	}
}

func ( *expression) ( *strings.Builder,  Values) error {
	 := true
	for ,  := range .vars {
		 := .Get(.name)
		if !.Valid() {
			continue
		}

		if  {
			.WriteString(.first)
			 = false
		} else {
			.WriteString(.sep)
		}

		if  := .expand(, , );  != nil {
			return 
		}

	}
	return nil
}

func ( *expression) ( *strings.Builder) {
	if .first != "" {
		.WriteString("(?:") // $1
		.WriteString(regexp.QuoteMeta(.first))
	}
	.WriteByte('(') // $2
	runeClassToRegexp(, .allow, .named || .vars[0].explode)
	if len(.vars) > 1 || .vars[0].explode {
		 := len(.vars) - 1
		for  := 0;  < len(.vars); ++ {
			if .vars[].explode {
				 = -1
				break
			}
		}

		.WriteString("(?:") // $3
		.WriteString(regexp.QuoteMeta(.sep))
		runeClassToRegexp(, .allow, .named ||  < 0)
		.WriteByte(')') // $3
		if  > 0 {
			.WriteString("{0,")
			.WriteString(strconv.Itoa())
			.WriteByte('}')
		} else {
			.WriteByte('*')
		}
	}
	.WriteByte(')') // $2
	if .first != "" {
		.WriteByte(')') // $1
	}
	.WriteByte('?')
}

func runeClassToRegexp( *strings.Builder,  runeClass,  bool) {
	.WriteString("(?:(?:[")
	if &runeClassR == 0 {
		.WriteString(`\x2c`)
		if  {
			.WriteString(`\x3d`)
		}
	}
	if &runeClassU == runeClassU {
		.WriteString(reUnreserved)
	}
	if &runeClassR == runeClassR {
		.WriteString(reReserved)
	}
	.WriteString("]")
	.WriteString("|%[[:xdigit:]][[:xdigit:]]")
	.WriteString(")*)")
}