// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package match

import (
	"regexp"
	"regexp/syntax"
)

func compile(r *syntax.Regexp) (stringMatcher, error) {
	switch {
	case r.Op == syntax.OpLiteral:
		s := string(r.Rune)
		return &substringMatcher{s, []byte(s)}, nil

	case isExactLiteral(r):
		s := string(r.Sub[1].Rune)
		return &equalsMatcher{s, []byte(s)}, nil

	case isAltLiterals(r):
		var literals [][]byte
		for _, sub := range r.Sub {
			literals = append(literals, []byte(string(sub.Rune)))
		}
		return &altSubstringMatcher{literals}, nil

	case isOneOfLiterals(r):
		var literals [][]byte
		for _, sub := range r.Sub[1].Sub {
			literals = append(literals, []byte(string(sub.Rune)))
		}
		return &oneOfMatcher{literals}, nil

	case isPrefixLiteral(r):
		s := []byte(string(r.Sub[1].Rune))
		return &prefixMatcher{s}, nil

	case isPrefixAltLiterals(r):
		var literals [][]byte
		for _, sub := range r.Sub[1].Sub {
			literals = append(literals, []byte(string(sub.Rune)))
		}
		return &altPrefixMatcher{literals}, nil

	case isPrefixNumDate(r):
		return compilePrefixNumDate(r)

	case isEmptyText(r):
		var m *emptyStringMatcher
		return m, nil

	case isEmptyTextWithWhitespace(r):
		var m *emptyWhiteStringMatcher
		return m, nil

	case isAnyMatch(r):
		var m *matchAny
		return m, nil

	default:

		r, err := regexp.Compile(r.String())
		if err != nil {
			return nil, err
		}
		return r, nil
	}
}

func compilePrefixNumDate(r *syntax.Regexp) (stringMatcher, error) {
	m := &prefixNumDate{}

	i := 1
	if r.Sub[i].Op == syntax.OpLiteral {
		m.prefix = []byte(string(r.Sub[i].Rune))
		i++
	}

	digitLen := func(r *syntax.Regexp) int {
		if r.Op == syntax.OpConcat {
			return len(r.Sub)
		}
		return 1
	}

	var digits []int
	var seps [][]byte

	digits = append(digits, digitLen(r.Sub[i]))
	i++

	for i < len(r.Sub) {
		lit := []byte(string(r.Sub[i].Rune))
		i++

		// capture literal suffix
		if i == len(r.Sub) {
			m.suffix = lit
			break
		}

		seps = append(seps, lit)
		digits = append(digits, digitLen(r.Sub[i]))
		i++
	}

	minLen := len(m.prefix) + len(m.suffix)
	for _, d := range digits {
		minLen += d
	}
	for _, sep := range seps {
		minLen += len(sep)
	}

	m.digits = digits
	m.seps = seps
	m.minLen = minLen

	return m, nil
}
