outfmt.gno

package outfmt

import (
	"math/rand"
	"strconv"
	"strings"

	"gno.land/p/nt/ufmt/v0"
)

type Result struct {
	Number  int
	Text    string
	Numbers []int
}

func (res *Result) String() string {
	output := ufmt.Sprintf("Text: %s\n", res.Text)
	output += ufmt.Sprintf("Number: %d\n", res.Number)

	output += "Numbers:"
	for _, number := range res.Numbers {
		output += ufmt.Sprintf(" %d", number)
	}
	output += "\n"

	return output
}

var rSeed = rand.NewPCG(0, 0)

func genResult() Result {
	r := rand.New(rSeed)

	// init rand
	res := Result{
		Text:   "Hello Gnomes!",
		Number: r.IntN(1000),
	}

	length := r.IntN(8) + 2
	res.Numbers = make([]int, length)
	for i := 0; i < length; i++ {
		res.Numbers[i] = r.IntN(100)
	}

	return res
}

// marshal function to manually convert struct to JSON string
func (r Result) marshal() string {
	// Start JSON string
	jsonStr := `{"Number":` + strconv.Itoa(r.Number) + `,"Text":"` + r.Text + `","Numbers":[`

	for i, num := range r.Numbers {
		jsonStr += strconv.Itoa(num)
		if i < len(r.Numbers)-1 {
			jsonStr += ","
		}
	}

	jsonStr += "]}"

	return jsonStr
}

func Render(path string) string {
	if path == "" {
		output := ""
		output += "* [?fmt=stringer](/r/moul/outfmt:?fmt=stringer)\n"
		output += "* [?fmt=json](/r/moul/outfmt:?fmt=json)\n"
		output += "* [?fmt=jsonp](/r/moul/outfmt:?fmt=jsonp)\n"
		return output
	}

	// parsing
	fmt := "stringer" // default
	// FIXME: whitelist and use net/url.
	{
		parts := strings.Split(path, "?")
		if len(parts) == 2 {
			// path := parts[0]
			query := parts[1]
			if query != "" {
				parts = strings.Split(query, "=")
				if len(parts) == 2 {
					k := parts[0]
					v := parts[1]
					if k == "fmt" {
						fmt = v
					}
				}
			}
		}
	}

	// rendering

	res := genResult()
	switch fmt {
	case "stringer":
		return res.String()
	case "json":
		// FIXME: return content-type?
		out := res.marshal()
		return string(out)
	case "jsonp":
		// FIXME: return content-type?
		callback := "callback" // FIXME: get it from query
		out := res.marshal()
		return callback + "(" + string(out) + ")"
	default:
		panic("unknown format")
	}
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}