package main

import (
	"encoding/json"
	"fmt"
	"strconv"
)

func main() {
	encode("hello")
	encode(25)
	encode(map[string]string{"color": "green", "temperature": "95", "speed": "100"})
	encode(Email{name: "gopher", domain: "golang.org"})
}

func encode(v interface{}) {
	var result []byte
	switch t := v.(type) {
	case json.Marshaler:
		result = encodeMarshaler(t)
	case map[string]string:
		result = encodeMap(t)
	case string:
		result = encodeString(t)
	case int:
		result = encodeInt(t)
	default:
		fmt.Printf("unable to encode type %T\n", t)
	}
	fmt.Println(string(result))
}

func encodeMarshaler(m json.Marshaler) []byte {
	b, err := m.MarshalJSON()
	if err != nil {
		panic(fmt.Sprintf("error encoding %T: %s\n", m, err))
	}
	return b
}

func encodeMap(m map[string]string) []byte {
	js := "{"
	for k, v := range m {
		js = js + `"` + k + `":"` + v + `" `
	}
	js = js + "}"
	return []byte(js)
}

func encodeString(s string) []byte {
	fmt := `{"value":"` + s + `"}"`
	return []byte(fmt)
}

func encodeInt(i int) []byte {
	fmt := `{"value":"` + strconv.Itoa(i) + `"}"`
	return []byte(fmt)
}

type Email struct {
	name   string
	domain string
}

func (e Email) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("{\"email\":\"%s@%s\"}", e.name, e.domain)), nil
}
