// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// operator-context-value.go
package expr

//-------- context term

func newContextTerm(tk *Token) (inst *term) {
	return &term{
		tk:       *tk,
		children: make([]*term, 0, 1),
		position: posPrefix,
		priority: priIncDec,
		evalFunc: evalContextValue,
	}
}

func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) {
	var childValue any

	var sourceCtx ExprContext
	if len(opTerm.children) == 0 {
		sourceCtx = ctx
	} else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].source() == "global" {
		sourceCtx = globalCtx
	} else if childValue, err = opTerm.evalPrefix(ctx); err == nil {
		if dc, ok := childValue.(*dataCursor); ok {
			sourceCtx = dc.ctx
		}
	}

	if sourceCtx != nil {
		if formatter, ok := sourceCtx.(DictFormat); ok {
			v = formatter.ToDict()
		} else if formatter, ok := sourceCtx.(Formatter); ok {
			v = formatter.ToString(0)
		} else {
			// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
			keys := sourceCtx.EnumVars(nil)
			d := make(map[string]any)
			for _, key := range keys {
				d[key], _ = sourceCtx.GetVar(key)
			}
			keys = sourceCtx.EnumFuncs(func(name string) bool { return true })
			for _, key := range keys {
				d[key], _ = sourceCtx.GetFuncInfo(key)
			}
			v = d
		}
	} else {
		err = opTerm.errIncompatibleType(childValue)
	}
	return
}

// init
func init() {
	registerTermConstructor(SymDoubleDollar, newContextTerm)
}