package routes

import (
	"fmt"
	"regexp"
	"strings"
)

const (
	wildcardSymbol = "*"
	globSymbol     = "$"
)

var (
	wildcardPattern *regexp.Regexp = regexp.MustCompile(`\:\w+`)
	globPattern     *regexp.Regexp = regexp.MustCompile(`\*\w+`)
)

// Replace wildcards with "*" in the given path
func cleanWildcards(path string) string {
	return wildcardPattern.ReplaceAllLiteralString(path, wildcardSymbol)
}

// Replace glob expressions with "$" in the given path
func cleanGlobs(path string) string {
	return globPattern.ReplaceAllLiteralString(path, globSymbol)
}

// returns true if `s` matches `w`, where `w` is string with a
// trailing wildcard, eg `.format*`
func wildcardMatch(s string, w string) bool {
	return strings.HasPrefix(s, w[:strings.Index(w, wildcardSymbol)])
}

func iswildcardSymbolPattern(s string) bool {
	return strings.Index(s, wildcardSymbol) != -1
}

// For each set of parentheses, return 2 versions: 1 with the
// parenthesized field left in, 1 with it left out.
func normalizeParens(pattern string) []string {
	// make sure the input isn't pathological, since the algorithm
	// below is Θ(2^n) with n=number of parenthesized statements
	if strings.Count(pattern, "(") > 15 {
		panic(fmt.Sprintf("pattern %s contains too many parenthesized statements", pattern))
	}
	// keep track of how deep we are into parentheses
	depth := 0
	// maintain a separate 'workspace' for each depth level - just a
	// list of valid patterns per depth
	patterns := make(map[int][]string)
	// initialize the 0-depth pattern to empty string
	patterns[0] = []string{""}
	for _, rune := range pattern {
		switch rune {
		case '(':
			// Enter a parenthesized statement
			depth += 1
			// Copy the workspace from above. Until we hit a ), new
			// characters are only appended to patterns at this depth.
			patterns[depth] = make([]string, len(patterns[depth-1]))
			copy(patterns[depth], patterns[depth-1])
		case ')':
			// Exit parenthesized statement
			// Our workspace at this depth is now complete. Append it
			// to the set of valid paths at the above level.
			patterns[depth-1] = append(patterns[depth-1], patterns[depth]...)
			depth -= 1
		default:
			// Just a normal character
			// For all patterns in the current depth, tack this
			// character at the end
			for i := range patterns[depth] {
				patterns[depth][i] += string(rune)
			}
		}
	}
	// All patterns should be bubbled up to the top level now
	if depth != 0 {
		panic(fmt.Sprintf("mismatched parentheses: %s", pattern))
	}
	return patterns[0]
}
