package main

import "strconv"

type char struct {
	modifier bool
	char     byte
}

func ParseRange(pattern string) []byte {

	chars := tokenize(pattern)
	var bytes []byte
	l := len(chars)

	for i := 0; i < l; i++ {

		if i+1 < l && chars[i+1].char == '-' && chars[i+1].modifier {
			bytes = append(bytes, expand(chars[i].char, chars[i+2].char)...)
			i += 2
		} else {
			bytes = append(bytes, chars[i].char)
		}

	}

	return bytes

}

func tokenize(pattern string) []char {

	var chars []char
	l := len(pattern)

	for i := 0; i < l; i++ {

		literal := literal(pattern, &i)

		if literal != nil {
			chars = append(chars, *literal)
			continue
		}

		if pattern[i] == '-' && i+1 < l {

			lc := len(chars)

			// Previous character must not be a range modifier, and it must not be a boundary of previous range.
			if lc > 0 && !chars[lc-1].modifier && (lc == 1 || !(chars[lc-2].modifier && chars[lc-2].char == '-')) {
				chars = append(chars, char{true, '-'})
				continue
			}

		}

		chars = append(chars, char{false, pattern[i]})

	}

	return chars

}

func literal(pattern string, i *int) *char {

	for j := *i + 1; pattern[*i] == '{' && j < len(pattern); j++ {

		if pattern[j] == '}' {

			n, err := strconv.Atoi(pattern[*i+1 : j])

			if err == nil && n >= 0 && n <= 0xff {
				*i = j
				return &char{false, byte(n)}
			}

		}

	}

	return nil

}

func expand(start byte, end byte) []byte {

	if start > end {
		start, end = end, start
	}

	bytes := make([]byte, end-start+1)

	for i := start; i <= end; i++ {
		bytes[i-start] = i
	}

	return bytes

}