package main // import "4d63.com/embedfiles"

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io/ioutil"
	"os"
	"path/filepath"
	"text/template"
)

const tmpl = `
// Generated by 4d63.com/embedfiles.

package {{.Package}}

var {{.FileNamesVar}} = []string{ {{range $name, $bytes := .Files}}"{{$name}}",{{end}} }

var {{.FilesVar}} = map[string][]byte{
{{range $name, $bytes := .Files}}
	"{{$name}}": []byte{ {{range $bytes}}{{.}},{{end}} },
{{end}}
}
`

type tmplData struct {
	Package      string
	Files        map[string][]byte
	FileNamesVar string
	FilesVar     string
}

func main() {
	out := flag.String("out", "files.go", "output go `file`")
	pkg := flag.String("pkg", "main", "`package` name of the go file")
	filesVar := flag.String("files-var", "files", "name of the generated files slice")
	fileNamesVar := flag.String("file-names-var", "fileNames", "name of the generated file names slice")
	verbose := flag.Bool("verbose", false, "")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Embedfiles embeds files in the paths into a map in a go file.\n\n")
		fmt.Fprintf(os.Stderr, "Usage:\n\n")
		fmt.Fprintf(os.Stderr, "  embedfiles -out=files.go -pkg=main <paths>\n\n")
		fmt.Fprintf(os.Stderr, "Flags:\n\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	inputPaths := flag.Args()

	if len(inputPaths) == 0 {
		flag.Usage()
		return
	}

	f, err := os.Create(*out)
	if err != nil {
		printErr("creating file", err)
		return
	}

	files := map[string][]byte{}
	for _, inputPath := range inputPaths {
		err = filepath.Walk(inputPath, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return fmt.Errorf("walking: %s", err)
			}

			if info.IsDir() {
				return nil
			}

			if *verbose {
				fmt.Printf("%s ", path)
			}

			contents, err := ioutil.ReadFile(path)
			if err != nil {
				return fmt.Errorf("reading file: %s", err)
			}
			if *verbose {
				fmt.Printf("(%d bytes)\n", len(contents))
			}

			path = filepath.ToSlash(path)
			files[path] = contents
			return nil
		})
		if err != nil {
			printErr("walking", err)
			return
		}
	}

	t, err := template.New("").Parse(tmpl)
	if err != nil {
		printErr("parsing template", err)
		return
	}

	buf := bytes.Buffer{}
	err = t.Execute(&buf, &tmplData{Package: *pkg, Files: files, FilesVar: *filesVar, FileNamesVar: *fileNamesVar})
	if err != nil {
		printErr("generating code", err)
		return
	}

	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		printErr("formatting code", err)
		return
	}

	f.Write(formatted)
	err = f.Close()
	if err != nil {
		printErr("finalizing file", err)
		return
	}
}

func printErr(doing string, err error) {
	fmt.Fprintf(os.Stderr, "Error %s: %s\n", doing, err)
}
