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

// formatter.go
package expr

import "fmt"

type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number

const (
	TTY FmtOpt = 1 << iota
	MultiLine
	Truncate
	Base2
	Base8
	Base10
	Base16
)

const (
	TruncateEllipsis = "(...)"
	MinTruncateSize  = 10
	TruncateSize     = MinTruncateSize + 15
)

func TruncateString(s string) (trunc string) {
	finalPart := len(s) - (MinTruncateSize - len(TruncateEllipsis))
	trunc = s[0:len(s)-MinTruncateSize] + TruncateEllipsis + s[finalPart:]
	return
}

func MakeFormatOptions(flags FmtOpt, indent int) FmtOpt {
	return FmtOpt(indent<<16) | flags
}

func GetFormatFlags(opt FmtOpt) FmtOpt {
	return opt & 0xFFFF
}

func GetFormatIndent(opt FmtOpt) int {
	return int(opt >> 16)
}

type Formatter interface {
	ToString(options FmtOpt) string
}

func getFormatted(v any, opt FmtOpt) (text string) {
	if v == nil {
		text = "(nil)"
	} else if s, ok := v.(string); ok {
		text = s
	} else if formatter, ok := v.(Formatter); ok {
		text = formatter.ToString(opt)
	} else {
		text = fmt.Sprintf("%v", v)
	}
	return
}

type Typer interface {
	TypeName() string
}

func TypeName(v any) (name string) {
	if v == nil {
		name = "nil"
	} else if typer, ok := v.(Typer); ok {
		name = typer.TypeName()
	} else if IsInteger(v) {
		name = "integer"
	} else if IsFloat(v) {
		name = "float"
	} else {
		name = fmt.Sprintf("%T", v)
	}
	return
}
