// Copyright 2020 CUE Authors
//
// Licensed 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 adt

// MatchAndInsert finds matching optional parts for a given Arc and adds its
// conjuncts. Bulk fields are only applied if no fields match, and additional
// constraints are only added if neither regular nor bulk fields match.
func (o *StructInfo) MatchAndInsert(c *OpContext, arc *Vertex) {
	env := o.Env

	closeInfo := o.CloseInfo
	closeInfo.IsClosed = false

	// Match normal fields
	matched := false
outer:
	for _, f := range o.Fields {
		if f.Label == arc.Label {
			for _, e := range f.Optional {
				arc.AddConjunct(MakeConjunct(env, e, closeInfo))
			}
			matched = true
			break outer
		}
	}

	f := arc.Label
	if !f.IsRegular() {
		return
	}
	if int64(f.Index()) == MaxIndex {
		f = 0
	}

	var label Value
	if o.types&HasComplexPattern != 0 && f.IsString() {
		label = f.ToValue(c)
	}

	if len(o.Bulk) > 0 {
		bulkEnv := *env
		bulkEnv.DynamicLabel = f
		bulkEnv.Deref = nil
		bulkEnv.Cycles = nil

		// match bulk optional fields / pattern properties
		for _, b := range o.Bulk {
			// if matched && f.additional {
			// 	continue
			// }
			if matchBulk(c, env, b, f, label) {
				matched = true
				info := closeInfo.SpawnSpan(b.Value, ConstraintSpan)
				arc.AddConjunct(MakeConjunct(&bulkEnv, b, info))
			}
		}
	}

	if matched || len(o.Additional) == 0 {
		return
	}

	addEnv := *env
	addEnv.Deref = nil
	addEnv.Cycles = nil

	// match others
	for _, x := range o.Additional {
		info := closeInfo
		if _, ok := x.(*Top); !ok {
			info = info.SpawnSpan(x, ConstraintSpan)
		}
		arc.AddConjunct(MakeConjunct(&addEnv, x, info))
	}
}

// matchBulk reports whether feature f matches the filter of x. It evaluation of
// the filter is erroneous, it returns false and the error will  be set in c.
func matchBulk(c *OpContext, env *Environment, x *BulkOptionalField, f Feature, label Value) bool {
	v := env.evalCached(c, x.Filter)

	// Fast-track certain cases.
	switch x := v.(type) {
	case *Bottom:
		if c.errs == nil {
			c.AddBottom(x)
		}
		return false
	case *Top:
		return true

	case *BasicType:
		return x.K&StringKind != 0

	case *BoundValue:
		switch x.Kind() {
		case StringKind:
			if label == nil {
				return false
			}
			str := label.(*String).Str
			return x.validateStr(c, str)

		case IntKind:
			return x.validateInt(c, int64(f.Index()))
		}
	}

	if label == nil {
		return false
	}

	n := Vertex{}
	m := MakeRootConjunct(env, v)
	n.AddConjunct(m)
	n.AddConjunct(MakeRootConjunct(m.Env, label))

	c.inConstraint++
	n.Finalize(c)
	c.inConstraint--

	b, _ := n.BaseValue.(*Bottom)
	return b == nil
}
