// 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 (
	
	
	
	
)

var (
	debug = debugT(false)
)

type debugT bool

func ( debugT) ( string,  ...interface{}) {
	if  {
		log.Printf(, ...)
	}
}

// Template represents a URI Template.
type Template struct {
	raw   string
	exprs []template

	// protects the rest of fields
	mu       sync.Mutex
	varnames []string
	re       *regexp.Regexp
	prog     *prog
}

// New parses and constructs a new Template instance based on the template.
// New returns an error if the template cannot be recognized.
func ( string) (*Template, error) {
	return (&parser{r: }).parseURITemplate()
}

// MustNew panics if the template cannot be recognized.
func ( string) *Template {
	,  := New()
	if  != nil {
		panic()
	}
	return 
}

// Raw returns a raw URI template passed to New in string.
func ( *Template) () string {
	return .raw
}

// Varnames returns variable names used in the template.
func ( *Template) () []string {
	.mu.Lock()
	defer .mu.Unlock()
	if .varnames != nil {
		return .varnames
	}

	 := map[string]struct{}{}
	.varnames = []string{}
	for  := range .exprs {
		,  := .exprs[].(*expression)
		if ! {
			continue
		}
		for ,  := range .vars {
			if ,  := [.name];  {
				continue
			}
			[.name] = struct{}{}
			.varnames = append(.varnames, .name)
		}
	}

	return .varnames
}

// Expand returns a URI reference corresponding to the template expanded using the passed variables.
func ( *Template) ( Values) (string, error) {
	var  strings.Builder
	for  := range .exprs {
		 := .exprs[]
		if  := .expand(&, );  != nil {
			return .String(), 
		}
	}
	return .String(), nil
}

// Regexp converts the template to regexp and returns compiled *regexp.Regexp.
func ( *Template) () *regexp.Regexp {
	.mu.Lock()
	defer .mu.Unlock()
	if .re != nil {
		return .re
	}

	var  strings.Builder
	.WriteByte('^')
	for ,  := range .exprs {
		.regexp(&)
	}
	.WriteByte('$')
	.re = regexp.MustCompile(.String())

	return .re
}