/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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 ycfg

import (
	"fmt"
	"mynewt.apache.org/newt/newt/cfgv"
	"reflect"
	"strings"

	"github.com/spf13/cast"

	"mynewt.apache.org/newt/newt/parse"
	"mynewt.apache.org/newt/util"
	"mynewt.apache.org/newt/yaml"
)

// YAML configuration object.  This is a substitute for a viper configuration
// object, with the following newt-specific advantages:
// 1. Case sensitive.
// 2. Efficient conditionals based on syscfg values.
//
// A single YCfg setting is implemented as a tree of nodes.  Each word in the
// setting name represents a node; each "." in the name is a link in the tree.
// For example, the following syscfg lines:
//
// OS_MAIN_STACK_SIZE: 100
// OS_MAIN_STACK_SIZE.BLE_DEVICE: 200
// OS_MAIN_STACK_SIZE.SHELL_TASK: 300
//
// Is represented as the following tree:
//
//                      [OS_MAIN_STACK_SIZE (100)]
//                     /                          \
//            [BLE_DEVICE (200)]           [SHELL_TASK (300)]
//
// This allows us to quickly determine the value of OS_MAIN_STACK_SIZE.  After
// finding the OS_MAIN_STACK_SIZE node, the logic is something like this:
//
// Is BLE_DEVICE true? --> 200
// Is SHELL_TASK true? --> 300
// Else: --> 100
//
// The tree structure also allows for arbitrary expressions as conditionals, as
// opposed to simple setting names.  For example:
//
// OS_MAIN_STACK_SIZE: 100
// OS_MAIN_STACK_SIZE.'(BLE_DEVICE && !SHELL_TASK): 200
// OS_MAIN_STACK_SIZE.'(SHELL_TASK && !BLE_DEVICE): 300
// OS_MAIN_STACK_SIZE.'(SHELL_TASK && BLE_DEVICE):  400
//
// Since each expression is a child node of the setting in question, they are
// all known at the time of the lookup.  To determine the value of the setting,
// each expression is parsed, and only the one evaluating to true is selected.
type YCfg struct {
	// Name of config; typically a YAML filename.
	name string

	// The settings.
	tree YCfgTree
}

type YCfgEntry struct {
	Value interface{}
	Expr  *parse.Node
}

type YCfgNode struct {
	Overwrite bool
	Name      string
	Value     interface{}
	Children  YCfgTree
	Parent    *YCfgNode
	FileInfo  *util.FileInfo
}

type YCfgTree map[string]*YCfgNode

func (yc *YCfg) Tree() YCfgTree {
	return yc.tree
}

func NewYCfgNode() *YCfgNode {
	return &YCfgNode{Children: YCfgTree{}}
}

func (node *YCfgNode) addChild(name string) (*YCfgNode, error) {
	if node.Children == nil {
		node.Children = YCfgTree{}
	}

	if node.Children[name] != nil {
		return nil, fmt.Errorf("Duplicate YCfgNode: %s", name)
	}

	child := NewYCfgNode()
	child.Name = name
	child.Parent = node

	node.Children[name] = child

	return child, nil
}

func (yc *YCfg) ReplaceFromFile(key string, val interface{},
	fileInfo *util.FileInfo) error {

	elems := strings.Split(key, ".")
	if len(elems) == 0 {
		return fmt.Errorf("Invalid ycfg key: \"\"")
	}

	var overwrite bool
	if elems[len(elems)-1] == "OVERWRITE" {
		overwrite = true
		elems = elems[:len(elems)-1]
	}

	var parent *YCfgNode
	for i, e := range elems {
		var parentChildren YCfgTree
		if parent == nil {
			parentChildren = yc.tree
		} else {
			if parent.Children == nil {
				parent.Children = YCfgTree{}
			}
			parentChildren = parent.Children
		}
		child := parentChildren[e]
		if child == nil {
			var err error
			if parent != nil {
				child, err = parent.addChild(e)
				if err != nil {
					return err
				}
			} else {
				child = NewYCfgNode()
				child.Name = e
				parentChildren[e] = child
			}
		}

		if i == len(elems)-1 {
			child.Overwrite = overwrite
			child.Value = val
		}
		child.FileInfo = fileInfo

		parent = child
	}

	return nil
}

// MergeFromFile merges the given value into a tree node.  Only two value types
// can be merged:
//
//     map[interface{}]interface{}
//     []interface{}
//
// The node's current value must have the same type as the value being merged.
// In the map case, each key-value pair in the given value is inserted into the
// current value, overwriting as necessary.  In the slice case, the given value
// is appended to the current value.
//
// If no node with the specified key exists, a new node is created containing
// the given value.
func (yc *YCfg) MergeFromFile(key string, val interface{},
	fileInfo *util.FileInfo) error {

	// Find the node being merged into.
	node := yc.find(key)

	// If the node doesn't exist, create one with the new value.
	if node == nil || node.Value == nil {
		return yc.ReplaceFromFile(key, val, fileInfo)
	}

	// The null value gets interpreted as an empty string during YAML
	// parsing.  A null merge is a no-op.
	if s, ok := val.(string); ok && s == "" {
		val = nil
	}
	if val == nil {
		return nil
	}

	mergeErr := func() error {
		return util.FmtNewtError(
			"can't merge type %T into cfg node \"%s\"; node type: %T",
			val, key, node.Value)
	}

	switch nodeVal := node.Value.(type) {
	case map[interface{}]interface{}:
		newVal, ok := val.(map[interface{}]interface{})
		if !ok {
			return mergeErr()
		}
		for k, v := range newVal {
			nodeVal[k] = v
		}

	case []interface{}:
		newVal, ok := val.([]interface{})
		if !ok {
			return mergeErr()
		}
		node.Value = append(nodeVal, newVal...)

	default:
		return mergeErr()
	}

	return nil
}

func (yc *YCfg) Replace(key string, val interface{}) error {
	return yc.ReplaceFromFile(key, val, nil)
}

func NewYCfg(name string) YCfg {
	return YCfg{
		name: name,
		tree: YCfgTree{},
	}
}

func (yc *YCfg) find(key string) *YCfgNode {
	elems := strings.Split(key, ".")
	if len(elems) == 0 {
		return nil
	}

	cur := &YCfgNode{
		Children: yc.tree,
	}
	for _, e := range elems {
		if cur.Children == nil {
			return nil
		}

		cur = cur.Children[e]
		if cur == nil {
			return nil
		}
	}

	return cur
}

func (yc *YCfg) HasKey(key string) bool {
	return yc.find(key) != nil
}

// Get retrieves all nodes with the specified key.  If it encounters a parse
// error in the tree, it ignores the bad node and continues the search.  All
// bad nodes are indicated in the returned error.  In this sense, the returned
// object is valid even if there is an error, and the error can be thought of
// as a set of warnings.
func (yc *YCfg) Get(key string,
	settings *cfgv.Settings) ([]YCfgEntry, error) {

	node := yc.find(key)
	if node == nil {
		return nil, nil
	}

	entries := []YCfgEntry{}

	if node.Value != nil {
		entry := YCfgEntry{Value: node.Value}
		entries = append(entries, entry)
	}

	var errLines []string
	for _, child := range node.Children {
		expr, err := parse.LexAndParse(child.Name)
		if err != nil {
			errLines = append(errLines,
				fmt.Sprintf("%s: %s", yc.name, err.Error()))
			continue
		}
		val, err := parse.Eval(expr, settings)
		if err != nil {
			errLines = append(errLines,
				fmt.Sprintf("%s: %s", yc.name, err.Error()))
			continue
		}
		if val {
			entry := YCfgEntry{
				Value: child.Value,
				Expr:  expr,
			}
			if child.Overwrite {
				entries = []YCfgEntry{entry}
				break
			}

			entries = append(entries, entry)
		}
	}

	if len(errLines) > 0 {
		return entries, util.NewNewtError(strings.Join(errLines, "\n"))
	} else {
		return entries, nil
	}
}

// GetSlice retrieves all entries with the specified key and coerces their
// values to type []interface{}.  The returned []YCfgEntry is formed from the
// union of all these slices.  The returned error is a set of warnings just as
// in `Get`.
func (yc *YCfg) GetSlice(key string, settings *cfgv.Settings) ([]YCfgEntry, error) {
	sliceEntries, getErr := yc.Get(key, settings)
	if len(sliceEntries) == 0 {
		return nil, getErr
	}

	result := []YCfgEntry{}
	for _, sliceEntry := range sliceEntries {
		if sliceEntry.Value != nil {
			slice, err := cast.ToSliceE(sliceEntry.Value)
			if err != nil {
				// Not a slice.  Put the single value in a new slice.
				slice = []interface{}{sliceEntry.Value}
			}
			for _, v := range slice {
				entry := YCfgEntry{
					Value: v,
					Expr:  sliceEntry.Expr,
				}
				result = append(result, entry)
			}
		}
	}

	return result, getErr
}

// GetValSlice retrieves all entries with the specified key and coerces their
// values to type []interface{}.  The returned slice is the union of all these
// slices. The returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValSlice(
	key string, settings *cfgv.Settings) ([]interface{}, error) {

	entries, getErr := yc.GetSlice(key, settings)
	if len(entries) == 0 {
		return nil, getErr
	}

	vals := make([]interface{}, len(entries))
	for i, e := range entries {
		vals[i] = e.Value
	}

	return vals, getErr
}

// GetStringSlice retrieves all entries with the specified key and coerces
// their values to type []string.  The returned []YCfgEntry is formed from the
// union of all these slices.  The returned error is a set of warnings just as
// in `Get`.
func (yc *YCfg) GetStringSlice(key string,
	settings *cfgv.Settings) ([]YCfgEntry, error) {

	sliceEntries, getErr := yc.Get(key, settings)
	if len(sliceEntries) == 0 {
		return nil, getErr
	}

	result := []YCfgEntry{}
	for _, sliceEntry := range sliceEntries {
		if sliceEntry.Value != nil {
			slice, err := cast.ToStringSliceE(sliceEntry.Value)
			if err != nil {
				// Not a slice.  Put the single value in a new slice.
				slice = []string{cast.ToString(sliceEntry.Value)}
			}
			for _, v := range slice {
				entry := YCfgEntry{
					Value: v,
					Expr:  sliceEntry.Expr,
				}
				result = append(result, entry)
			}
		}
	}

	return result, getErr
}

// GetValStringSlice retrieves all entries with the specified key and coerces
// their values to type []string.  The returned []string is the union of all
// these slices.  The returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValStringSlice(
	key string, settings *cfgv.Settings) ([]string, error) {

	entries, getErr := yc.GetStringSlice(key, settings)
	if len(entries) == 0 {
		return nil, getErr
	}

	vals := make([]string, len(entries))
	for i, e := range entries {
		if e.Value != nil {
			vals[i] = cast.ToString(e.Value)
		}
	}

	return vals, getErr
}

// GetValStringSliceNonempty retrieves all entries with the specified key and
// coerces their values to type []string.  The returned []string is the union
// of all these slices.  Empty strings are excluded from this union.  The
// returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValStringSliceNonempty(
	key string, settings *cfgv.Settings) ([]string, error) {

	strs, getErr := yc.GetValStringSlice(key, settings)
	filtered := make([]string, 0, len(strs))
	for _, s := range strs {
		if s != "" {
			filtered = append(filtered, s)
		}
	}

	return filtered, getErr
}

// GetStringMap retrieves all entries with the specified key and coerces their
// values to type map[string]interface{}.  The returned map[string]YCfgEntry is
// formed from the union of all these maps.  The returned error is a set of
// warnings just as in `Get`.
func (yc *YCfg) GetStringMap(
	key string, settings *cfgv.Settings) (map[string]YCfgEntry, error) {

	mapEntries, getErr := yc.Get(key, settings)
	if len(mapEntries) == 0 {
		return nil, getErr
	}

	result := map[string]YCfgEntry{}

	for _, mapEntry := range mapEntries {
		for k, v := range cast.ToStringMap(mapEntry.Value) {
			entry := YCfgEntry{
				Value: v,
				Expr:  mapEntry.Expr,
			}

			if _, exists := result[k]; exists {
				if !reflect.DeepEqual(entry.Value, result[k].Value) && (result[k].Expr != nil) && (entry.Expr != nil) {
					return nil, fmt.Errorf("setting %s collision - two conditions true:\n[%s, %s]\n"+
						"Conflicting file: %s",
						k, entry.Expr.String(), result[k].Expr.String(), yc.name)
				}
			}
			result[k] = entry
		}
	}

	return result, getErr
}

// GetValStringMap retrieves all entries with the specified key and coerces
// their values to type map[string]interface{}.  The returned
// map[string]YCfgEntry is the union of all these maps.  The returned error is
// a set of warnings just as in `Get`.
func (yc *YCfg) GetValStringMap(
	key string, settings *cfgv.Settings) (map[string]interface{}, error) {

	entryMap, getErr := yc.GetStringMap(key, settings)

	smap := make(map[string]interface{}, len(entryMap))
	for k, v := range entryMap {
		if v.Value != nil {
			smap[k] = v.Value
		}
	}

	return smap, getErr
}

// GetFirst retrieves the first entry with the specified key.  The bool return
// value is true if a matching entry was found.  The returned error is a set of
// warnings just as in `Get`.
func (yc *YCfg) GetFirst(key string,
	settings *cfgv.Settings) (YCfgEntry, bool, error) {

	entries, getErr := yc.Get(key, settings)
	if len(entries) == 0 {
		return YCfgEntry{}, false, getErr
	}

	return entries[0], true, getErr
}

// GetFirstVal retrieves the first entry with the specified key and returns its
// value.  It returns nil if no matching entry is found.  The returned error is
// a set of warnings just as in `Get`.
func (yc *YCfg) GetFirstVal(key string,
	settings *cfgv.Settings) (interface{}, error) {

	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return nil, getErr
	}

	return entry.Value, getErr
}

// GetValString retrieves the first entry with the specified key and returns
// its value coerced to a string.  It returns "" if no matching entry is found.
// The returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValString(key string,
	settings *cfgv.Settings) (string, error) {

	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return "", getErr
	} else {
		return cast.ToString(entry.Value), getErr
	}
}

// GetValInt retrieves the first entry with the specified key and returns its
// value coerced to an int.  It returns 0 if no matching entry is found.  The
// returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValInt(key string, settings *cfgv.Settings) (int, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return 0, getErr
	} else {
		return cast.ToInt(entry.Value), getErr
	}
}

// GetValIntDflt retrieves the first entry with the specified key and returns its
// value coerced to an int.  It returns the specified default if no matching entry
// is found.  The returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValIntDflt(key string, settings *cfgv.Settings, dflt int) (int, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return dflt, getErr
	} else {
		return cast.ToInt(entry.Value), getErr
	}
}

// GetValBoolDflt retrieves the first entry with the specified key and returns
// its value coerced to a bool.  It returns the specified default if no
// matching entry is found.  The returned error is a set of warnings just as in
// `Get`.
func (yc *YCfg) GetValBoolDflt(key string, settings *cfgv.Settings,
	dflt bool) (bool, error) {

	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return dflt, getErr
	} else {
		return cast.ToBool(entry.Value), getErr
	}
}

// GetValBoolDflt retrieves the first entry with the specified key and returns
// its value coerced to a bool.  It returns false if no matching entry is
// found.  The returned error is a set of warnings just as in `Get`.
func (yc *YCfg) GetValBool(key string,
	settings *cfgv.Settings) (bool, error) {

	return yc.GetValBoolDflt(key, settings, false)
}

// GetStringMapString retrieves all entries with the specified key and coerces
// their values to type map[string]string.  The returned map[string]YCfgEntry
// is formed from the union of all these maps.  The returned error is a set of
// warnings just as in `Get`.
func (yc *YCfg) GetStringMapString(key string,
	settings *cfgv.Settings) (map[string]YCfgEntry, error) {

	mapEntries, getErr := yc.Get(key, settings)
	if len(mapEntries) == 0 {
		return nil, getErr
	}

	result := map[string]YCfgEntry{}

	for _, mapEntry := range mapEntries {
		for k, v := range cast.ToStringMapString(mapEntry.Value) {
			entry := YCfgEntry{
				Value: v,
				Expr:  mapEntry.Expr,
			}

			if _, exists := result[k]; exists {
				if (entry.Value != result[k].Value) && (result[k].Expr != nil) {
					return nil, fmt.Errorf("Setting %s collision - two conditions true:\n[%s, %s]\n"+
						"Conflicting file: %s",
						k, entry.Expr.String(), result[k].Expr.String(), yc.name)
				}
			}
			result[k] = entry
		}
	}

	return result, getErr
}

// GetStringMapString retrieves all entries with the specified key and coerces
// their values to type map[string]string.  The returned map[string]YCfgEntry
// is the union of all these maps.  The returned error is a set of warnings
// just as in `Get`.
func (yc *YCfg) GetValStringMapString(key string,
	settings *cfgv.Settings) (map[string]string, error) {

	entryMap, getErr := yc.GetStringMapString(key, settings)
	if getErr != nil {
		return nil, getErr
	}

	valMap := make(map[string]string, len(entryMap))
	for k, v := range entryMap {
		if v.Value != nil {
			valMap[k] = cast.ToString(v.Value)
		}
	}

	return valMap, nil
}

// FullName calculates a node's name with the following form:
//     [...].<grandparent>.<parent>.<node>
func (node *YCfgNode) FullName() string {
	tokens := []string{}

	for n := node; n != nil; n = n.Parent {
		tokens = append(tokens, n.Name)
	}

	last := len(tokens) - 1
	for i := 0; i < len(tokens)/2; i++ {
		tokens[i], tokens[last-i] = tokens[last-i], tokens[i]
	}

	return strings.Join(tokens, ".")
}

// Delete deletes all entries with the specified key.
func (yc *YCfg) Delete(key string) {
	delete(yc.tree, key)
}

// Clear removes all entries from the YCfg.
func (yc *YCfg) Clear() {
	yc.tree = YCfgTree{}
}

// Traverse performs an in-order traversal of the YCfg tree.  The specified
// function is applied to each node.
func (yc *YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
	var traverseLevel func(
		node *YCfgNode,
		cb func(node *YCfgNode, depth int),
		depth int)

	traverseLevel = func(
		node *YCfgNode,
		cb func(node *YCfgNode, depth int),
		depth int) {

		cb(node, depth)
		for _, child := range node.Children {
			traverseLevel(child, cb, depth+1)
		}
	}

	for _, n := range yc.tree {
		traverseLevel(n, cb, 0)
	}
}

// AllSettings converts the YCfg into a map with the following form:
//     <node-full-name>: <node-value>
func (yc *YCfg) AllSettings() map[string]interface{} {
	settings := map[string]interface{}{}

	yc.Traverse(func(node *YCfgNode, depth int) {
		if node.Value != nil {
			settings[node.FullName()] = node.Value
		}
	})

	return settings
}

// AllSettingsAsStrings converts the YCfg into a map with the following form:
//     <node-full-name>: <node-value>
//
// All values in the map have been coerced to strings.
func (yc *YCfg) AllSettingsAsStrings() map[string]string {
	settings := yc.AllSettings()
	smap := make(map[string]string, len(settings))
	for k, v := range settings {
		smap[k] = fmt.Sprintf("%v", v)
	}

	return smap
}

// String produces a user-friendly string representation of the YCfg.
func (yc *YCfg) String() string {
	lines := make([]string, 0, len(yc.tree))
	yc.Traverse(func(node *YCfgNode, depth int) {
		line := strings.Repeat(" ", depth*4) + node.Name
		if node.Value != nil {
			line += fmt.Sprintf(": %+v", node.Value)
		}
		lines = append(lines, line)
	})

	return strings.Join(lines, "\n")
}

// YAML converts the YCfg to a map and encodes the map as YAML.
func (yc *YCfg) YAML() string {
	return yaml.MapToYaml(yc.AllSettings())
}
