// +build ignore,OMIT

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"
)

const input = `
{
    "name":"Gopher",
    "birthdate": "2009/11/10",
    "shirt-size": "XS"
}
`

type Person struct {
	Name string
	Born time.Time
	Size ShirtSize
}

func (p Person) String() string {
	return fmt.Sprintf("%s was born on %v and uses a %v t-shirt",
		p.Name, p.Born.Format("Jan 2 2006"), p.Size)
}

type ShirtSize byte

const (
	NA ShirtSize = iota
	XS
	S
	M
	L
	XL
)

func (ss ShirtSize) String() string {
	sizes := map[ShirtSize]string{XS: "XS", S: "S", M: "M", L: "L", XL: "XL"}
	s, ok := sizes[ss]
	if !ok {
		return "invalid t-shirt size"
	}
	return s
}

func ParseShirtSize(s string) (ShirtSize, error) {
	sizes := map[string]ShirtSize{"XS": XS, "S": S, "M": M, "L": L, "XL": XL}
	ss, ok := sizes[s]
	if !ok {
		return NA, fmt.Errorf("invalid t-shirt size %q", s)
	}
	return ss, nil
}

func (p *Person) Parse(s string) error {
	var aux struct {
		Name string
		Born string `json:"birthdate"`
		Size string `json:"shirt-size"`
	}

	dec := json.NewDecoder(strings.NewReader(s))
	if err := dec.Decode(&aux); err != nil {
		return fmt.Errorf("decode person: %v", err)
	}

	p.Name = aux.Name
	born, err := time.Parse("2006/01/02", aux.Born)
	if err != nil {
		return fmt.Errorf("invalid date: %v", err)
	}
	p.Born = born
	p.Size, err = ParseShirtSize(aux.Size)
	return err
}

func main() {
	var p Person
	if err := p.Parse(input); err != nil {
		log.Fatalf("parse person: %v", err)
	}
	fmt.Println(p)
}
