package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html"
	"html/template"
	"io/ioutil"
	"os"
	"strings"

	"gopkg.in/yaml.v2"

	"code.senomas.com/go/util"
)

// Variables struct
type Variables struct {
	Env map[string]string
}

func parseYAML(text string) map[string]interface{} {
	val := make(map[string]interface{})
	err := yaml.Unmarshal([]byte(text), &val)
	util.Check("Invalid yaml [%s] %v", text, err)
	return val
}

func parseJSON(text string) map[string]interface{} {
	val := make(map[string]interface{})
	err := json.Unmarshal([]byte(text), &val)
	util.Check("Invalid json [%s] %v", text, err)
	return val
}

func value(vs ...interface{}) interface{} {
	for _, v := range vs {
		if v != nil {
			return v
		}
	}
	return nil
}

func cat(spacer string, va ...interface{}) string {
	var bb bytes.Buffer
	for k, v := range va {
		if k > 0 {
			bb.WriteString(spacer)
		}
		fmt.Fprintf(&bb, "%v", v)
	}
	return bb.String()
}

func split(v string, sep string) []string {
	return strings.Split(v, sep)
}

func ift(test bool, vt, vf interface{}) interface{} {
	if test {
		return vt
	}
	return vf
}

func get(v map[string]interface{}, key string) interface{} {
	return v[key]
}

func getMap(v map[string]interface{}, keys ...string) interface{} {
	var ok bool
	for _, kk := range keys {
		v, ok = v[kk].(map[string]interface{})
		if !ok {
			return nil
		}
	}
	return v
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(r)
		}
	}()

	funcMap := template.FuncMap{
		"parseYAML": parseYAML,
		"parseJSON": parseJSON,
		"value":     value,
		"cat":       cat,
		"ift":       ift,
		"split":     split,
		"get":       get,
		"getMap":    getMap,
	}

	var text []byte
	var err error

	if len(os.Args) != 2 {
		panic("Usage: gotmpl <template file>")
	}

	text, err = ioutil.ReadFile(os.Args[1])
	util.Check("Error %v", err)

	tmpl, err := template.New("config").Option("missingkey=zero").Funcs(funcMap).Parse(string(text))
	util.Check("Error %v", err)

	env := make(map[string]string)

	for _, v := range os.Environ() {
		splits := strings.Split(v, "=")
		env[splits[0]] = strings.Join(splits[1:], "=")
	}

	var bb bytes.Buffer
	err = tmpl.Execute(&bb, &Variables{env})
	util.Check("Execute error %v", err)
	fmt.Println(html.UnescapeString(bb.String()))
}