// Copyright 2014 Google Inc. All rights reserved.
//
// 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 proptools

import (
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"text/scanner"

	"github.com/google/blueprint/parser"
)

const maxUnpackErrors = 10

type UnpackError struct {
	Err error
	Pos scanner.Position
}

func (e *UnpackError) Error() string {
	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
}

// packedProperty helps to track properties usage (`used` will be true)
type packedProperty struct {
	property *parser.Property
	used     bool
}

// unpackContext keeps compound names and their values in a map. It is initialized from
// parsed properties.
type unpackContext struct {
	propertyMap map[string]*packedProperty
	errs        []error
}

// UnpackProperties populates the list of runtime values ("property structs") from the parsed properties.
// If a property a.b.c has a value, a field with the matching name in each runtime value is initialized
// from it. See PropertyNameForField for field and property name matching.
// For instance, if the input contains
//
//	{ foo: "abc", bar: {x: 1},}
//
// and a runtime value being has been declared as
//
//	var v struct { Foo string; Bar int }
//
// then v.Foo will be set to "abc" and v.Bar will be set to 1
// (cf. unpack_test.go for further examples)
//
// The type of a receiving field has to match the property type, i.e., a bool/int/string field
// can be set from a property with bool/int/string value, a struct can be set from a map (only the
// matching fields are set), and an slice can be set from a list.
// If a field of a runtime value has been already set prior to the UnpackProperties, the new value
// is appended to it (see somewhat inappropriately named ExtendBasicType).
// The same property can initialize fields in multiple runtime values. It is an error if any property
// value was not used to initialize at least one field.
func UnpackProperties(properties []*parser.Property, objects ...interface{}) (map[string]*parser.Property, []error) {
	var unpackContext unpackContext
	unpackContext.propertyMap = make(map[string]*packedProperty)
	if !unpackContext.buildPropertyMap("", properties) {
		return nil, unpackContext.errs
	}

	for _, obj := range objects {
		valueObject := reflect.ValueOf(obj)
		if !isStructPtr(valueObject.Type()) {
			panic(fmt.Errorf("properties must be *struct, got %s",
				valueObject.Type()))
		}
		unpackContext.unpackToStruct("", valueObject.Elem())
		if len(unpackContext.errs) >= maxUnpackErrors {
			return nil, unpackContext.errs
		}
	}

	// Gather property map, and collect any unused properties.
	// Avoid reporting subproperties of unused properties.
	result := make(map[string]*parser.Property)
	var unusedNames []string
	for name, v := range unpackContext.propertyMap {
		if v.used {
			result[name] = v.property
		} else {
			unusedNames = append(unusedNames, name)
		}
	}
	if len(unusedNames) == 0 && len(unpackContext.errs) == 0 {
		return result, nil
	}
	return nil, unpackContext.reportUnusedNames(unusedNames)
}

func (ctx *unpackContext) reportUnusedNames(unusedNames []string) []error {
	sort.Strings(unusedNames)
	var lastReported string
	for _, name := range unusedNames {
		// if 'foo' has been reported, ignore 'foo\..*' and 'foo\[.*'
		if lastReported != "" {
			trimmed := strings.TrimPrefix(name, lastReported)
			if trimmed != name && (trimmed[0] == '.' || trimmed[0] == '[') {
				continue
			}
		}
		ctx.errs = append(ctx.errs, &UnpackError{
			fmt.Errorf("unrecognized property %q", name),
			ctx.propertyMap[name].property.ColonPos})
		lastReported = name
	}
	return ctx.errs
}

func (ctx *unpackContext) buildPropertyMap(prefix string, properties []*parser.Property) bool {
	nOldErrors := len(ctx.errs)
	for _, property := range properties {
		name := fieldPath(prefix, property.Name)
		if first, present := ctx.propertyMap[name]; present {
			ctx.addError(
				&UnpackError{fmt.Errorf("property %q already defined", name), property.ColonPos})
			if ctx.addError(
				&UnpackError{fmt.Errorf("<-- previous definition here"), first.property.ColonPos}) {
				return false
			}
			continue
		}

		ctx.propertyMap[name] = &packedProperty{property, false}
		switch propValue := property.Value.Eval().(type) {
		case *parser.Map:
			ctx.buildPropertyMap(name, propValue.Properties)
		case *parser.List:
			// If it is a list, unroll it unless its elements are of primitive type
			// (no further mapping will be needed in that case, so we avoid cluttering
			// the map).
			if len(propValue.Values) == 0 {
				continue
			}
			if t := propValue.Values[0].Type(); t == parser.StringType || t == parser.Int64Type || t == parser.BoolType {
				continue
			}

			itemProperties := make([]*parser.Property, len(propValue.Values), len(propValue.Values))
			for i, expr := range propValue.Values {
				itemProperties[i] = &parser.Property{
					Name:     property.Name + "[" + strconv.Itoa(i) + "]",
					NamePos:  property.NamePos,
					ColonPos: property.ColonPos,
					Value:    expr,
				}
			}
			if !ctx.buildPropertyMap(prefix, itemProperties) {
				return false
			}
		}
	}

	return len(ctx.errs) == nOldErrors
}

func fieldPath(prefix, fieldName string) string {
	if prefix == "" {
		return fieldName
	}
	return prefix + "." + fieldName
}

func (ctx *unpackContext) addError(e error) bool {
	ctx.errs = append(ctx.errs, e)
	return len(ctx.errs) < maxUnpackErrors
}

func (ctx *unpackContext) unpackToStruct(namePrefix string, structValue reflect.Value) {
	structType := structValue.Type()

	for i := 0; i < structValue.NumField(); i++ {
		fieldValue := structValue.Field(i)
		field := structType.Field(i)

		// In Go 1.7, runtime-created structs are unexported, so it's not
		// possible to create an exported anonymous field with a generated
		// type. So workaround this by special-casing "BlueprintEmbed" to
		// behave like an anonymous field for structure unpacking.
		if field.Name == "BlueprintEmbed" {
			field.Name = ""
			field.Anonymous = true
		}

		if field.PkgPath != "" {
			// This is an unexported field, so just skip it.
			continue
		}

		propertyName := fieldPath(namePrefix, PropertyNameForField(field.Name))

		if !fieldValue.CanSet() {
			panic(fmt.Errorf("field %s is not settable", propertyName))
		}

		// Get the property value if it was specified.
		packedProperty, propertyIsSet := ctx.propertyMap[propertyName]

		origFieldValue := fieldValue

		// To make testing easier we validate the struct field's type regardless
		// of whether or not the property was specified in the parsed string.
		// TODO(ccross): we don't validate types inside nil struct pointers
		// Move type validation to a function that runs on each factory once
		switch kind := fieldValue.Kind(); kind {
		case reflect.Bool, reflect.String, reflect.Struct, reflect.Slice:
			// Do nothing
		case reflect.Interface:
			if fieldValue.IsNil() {
				panic(fmt.Errorf("field %s contains a nil interface", propertyName))
			}
			fieldValue = fieldValue.Elem()
			elemType := fieldValue.Type()
			if elemType.Kind() != reflect.Ptr {
				panic(fmt.Errorf("field %s contains a non-pointer interface", propertyName))
			}
			fallthrough
		case reflect.Ptr:
			switch ptrKind := fieldValue.Type().Elem().Kind(); ptrKind {
			case reflect.Struct:
				if fieldValue.IsNil() && (propertyIsSet || field.Anonymous) {
					// Instantiate nil struct pointers
					// Set into origFieldValue in case it was an interface, in which case
					// fieldValue points to the unsettable pointer inside the interface
					fieldValue = reflect.New(fieldValue.Type().Elem())
					origFieldValue.Set(fieldValue)
				}
				fieldValue = fieldValue.Elem()
			case reflect.Bool, reflect.Int64, reflect.String:
				// Nothing
			default:
				panic(fmt.Errorf("field %s contains a pointer to %s", propertyName, ptrKind))
			}

		case reflect.Int, reflect.Uint:
			if !HasTag(field, "blueprint", "mutated") {
				panic(fmt.Errorf(`int field %s must be tagged blueprint:"mutated"`, propertyName))
			}

		default:
			panic(fmt.Errorf("unsupported kind for field %s: %s", propertyName, kind))
		}

		if field.Anonymous && isStruct(fieldValue.Type()) {
			ctx.unpackToStruct(namePrefix, fieldValue)
			continue
		}

		if !propertyIsSet {
			// This property wasn't specified.
			continue
		}

		packedProperty.used = true
		property := packedProperty.property

		if HasTag(field, "blueprint", "mutated") {
			if !ctx.addError(
				&UnpackError{
					fmt.Errorf("mutated field %s cannot be set in a Blueprint file", propertyName),
					property.ColonPos,
				}) {
				return
			}
			continue
		}

		if isStruct(fieldValue.Type()) {
			if property.Value.Eval().Type() != parser.MapType {
				ctx.addError(&UnpackError{
					fmt.Errorf("can't assign %s value to map property %q",
						property.Value.Type(), property.Name),
					property.Value.Pos(),
				})
				continue
			}
			ctx.unpackToStruct(propertyName, fieldValue)
			if len(ctx.errs) >= maxUnpackErrors {
				return
			}
		} else if isSlice(fieldValue.Type()) {
			if unpackedValue, ok := ctx.unpackToSlice(propertyName, property, fieldValue.Type()); ok {
				ExtendBasicType(fieldValue, unpackedValue, Append)
			}
			if len(ctx.errs) >= maxUnpackErrors {
				return
			}

		} else {
			unpackedValue, err := propertyToValue(fieldValue.Type(), property)
			if err != nil && !ctx.addError(err) {
				return
			}
			ExtendBasicType(fieldValue, unpackedValue, Append)
		}
	}
}

// unpackSlice creates a value of a given slice type from the property which should be a list
func (ctx *unpackContext) unpackToSlice(
	sliceName string, property *parser.Property, sliceType reflect.Type) (reflect.Value, bool) {
	propValueAsList, ok := property.Value.Eval().(*parser.List)
	if !ok {
		ctx.addError(&UnpackError{
			fmt.Errorf("can't assign %s value to list property %q",
				property.Value.Type(), property.Name),
			property.Value.Pos(),
		})
		return reflect.MakeSlice(sliceType, 0, 0), false
	}
	exprs := propValueAsList.Values
	value := reflect.MakeSlice(sliceType, 0, len(exprs))
	if len(exprs) == 0 {
		return value, true
	}

	// The function to construct an item value depends on the type of list elements.
	var getItemFunc func(*parser.Property, reflect.Type) (reflect.Value, bool)
	switch exprs[0].Type() {
	case parser.BoolType, parser.StringType, parser.Int64Type:
		getItemFunc = func(property *parser.Property, t reflect.Type) (reflect.Value, bool) {
			value, err := propertyToValue(t, property)
			if err != nil {
				ctx.addError(err)
				return value, false
			}
			return value, true
		}
	case parser.ListType:
		getItemFunc = func(property *parser.Property, t reflect.Type) (reflect.Value, bool) {
			return ctx.unpackToSlice(property.Name, property, t)
		}
	case parser.MapType:
		getItemFunc = func(property *parser.Property, t reflect.Type) (reflect.Value, bool) {
			itemValue := reflect.New(t).Elem()
			ctx.unpackToStruct(property.Name, itemValue)
			return itemValue, true
		}
	case parser.NotEvaluatedType:
		getItemFunc = func(property *parser.Property, t reflect.Type) (reflect.Value, bool) {
			return reflect.New(t), false
		}
	default:
		panic(fmt.Errorf("bizarre property expression type: %v", exprs[0].Type()))
	}

	itemProperty := &parser.Property{NamePos: property.NamePos, ColonPos: property.ColonPos}
	elemType := sliceType.Elem()
	isPtr := elemType.Kind() == reflect.Ptr

	for i, expr := range exprs {
		itemProperty.Name = sliceName + "[" + strconv.Itoa(i) + "]"
		itemProperty.Value = expr
		if packedProperty, ok := ctx.propertyMap[itemProperty.Name]; ok {
			packedProperty.used = true
		}
		if isPtr {
			if itemValue, ok := getItemFunc(itemProperty, elemType.Elem()); ok {
				ptrValue := reflect.New(itemValue.Type())
				ptrValue.Elem().Set(itemValue)
				value = reflect.Append(value, ptrValue)
			}
		} else {
			if itemValue, ok := getItemFunc(itemProperty, elemType); ok {
				value = reflect.Append(value, itemValue)
			}
		}
	}
	return value, true
}

// propertyToValue creates a value of a given value type from the property.
func propertyToValue(typ reflect.Type, property *parser.Property) (reflect.Value, error) {
	var value reflect.Value
	var baseType reflect.Type
	isPtr := typ.Kind() == reflect.Ptr
	if isPtr {
		baseType = typ.Elem()
	} else {
		baseType = typ
	}

	switch kind := baseType.Kind(); kind {
	case reflect.Bool:
		b, ok := property.Value.Eval().(*parser.Bool)
		if !ok {
			return value, &UnpackError{
				fmt.Errorf("can't assign %s value to bool property %q",
					property.Value.Type(), property.Name),
				property.Value.Pos(),
			}
		}
		value = reflect.ValueOf(b.Value)

	case reflect.Int64:
		b, ok := property.Value.Eval().(*parser.Int64)
		if !ok {
			return value, &UnpackError{
				fmt.Errorf("can't assign %s value to int64 property %q",
					property.Value.Type(), property.Name),
				property.Value.Pos(),
			}
		}
		value = reflect.ValueOf(b.Value)

	case reflect.String:
		s, ok := property.Value.Eval().(*parser.String)
		if !ok {
			return value, &UnpackError{
				fmt.Errorf("can't assign %s value to string property %q",
					property.Value.Type(), property.Name),
				property.Value.Pos(),
			}
		}
		value = reflect.ValueOf(s.Value)

	default:
		return value, &UnpackError{
			fmt.Errorf("cannot assign %s value %s to %s property %s", property.Value.Type(), property.Value, kind, typ),
			property.NamePos}
	}

	if isPtr {
		ptrValue := reflect.New(value.Type())
		ptrValue.Elem().Set(value)
		return ptrValue, nil
	}
	return value, nil
}
