package loader

import (
	"crypto/md5"
	"dbweb/core"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

var (
	//存放文件名是否生成
	concatFileCache = map[string]bool{}
)

type (
	jsCSSFile struct {
		FileName    string
		MinFileName string
	}
	jsCSSMinifyFile struct {
		FileName string
		Minify   bool
	}
	jsCSSConcat []jsCSSMinifyFile
)

func (j jsCSSMinifyFile) write(w io.Writer, currentPath string) error {
	var fileName string
	//如果是斜杠开头，则从源代码根目录开始，否则从当前文件目录开始
	if strings.HasPrefix(j.FileName, "/") {
		fileName = filepath.Join(rootPath, j.FileName)
	} else {
		fileName = filepath.Join(currentPath, j.FileName)
	}
	f, err := os.Open(fileName)
	if err != nil {
		fmt.Println(fileName, err)
		return err
	}
	defer f.Close()
	if j.Minify {
		if err = m.Minify(filepath.Ext(j.FileName), w, f); err != nil {
			return err
		}
	} else {
		if _, err = io.Copy(w, f); err != nil {
			return err
		}
	}
	return nil
}

//生成唯一的文件名,不含路径和扩展名
func (jf jsCSSConcat) fileName() string {
	h := md5.New()
	for _, one := range jf {
		if _, err := h.Write([]byte(one.FileName)); err != nil {
			core.LOG.Panic(err)
		}
	}
	return base64.RawURLEncoding.EncodeToString(h.Sum(nil))
}
func (jf jsCSSConcat) concat(fileName, currentPath string) error {
	out, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer out.Close()
	for _, one := range jf {
		if err = one.write(out, currentPath); err != nil {
			return err
		}
		out.WriteString("\n")
	}
	return nil
}
func appendJSCSSFile(slice *[]jsCSSFile, names ...string) string {
	val := jsCSSFile{}
	switch len(names) {
	case 2:
		val.FileName = names[0]
		val.MinFileName = names[1]
	case 1:
		val.FileName = names[0]
	case 0:
		return ""
	default:
		core.LOG.Panic("newFiles param's num error")
	}
	*slice = append(*slice, val)
	return ""
}

func processViewFile(dest, src string, staticPath string, notMinify bool) error {
	currentPath := filepath.Dir(src)
	bys, err := ioutil.ReadFile(src)
	if err != nil {
		return err
	}
	t, err := template.New(filepath.Base(src)).Delims("[[", "]]").Funcs(template.FuncMap{
		"newFiles": func(names ...string) *[]jsCSSFile {
			rev := []jsCSSFile{}
			appendJSCSSFile(&rev, names...)
			return &rev
		},
		"append": appendJSCSSFile,
		"concat": func(slice *[]jsCSSFile) string {
			if len(*slice) == 0 {
				return ""
			}
			ext := filepath.Ext((*slice)[0].FileName)
			if len(ext) == 0 {
				core.LOG.Panic((*slice)[0].FileName)
			}
			jf := jsCSSConcat{}
			for _, one := range *slice {
				if notMinify {
					jf = append(jf, jsCSSMinifyFile{FileName: one.FileName})
				} else {
					if len(one.MinFileName) > 0 {
						jf = append(jf, jsCSSMinifyFile{FileName: one.MinFileName})
					} else {
						jf = append(jf, jsCSSMinifyFile{FileName: one.FileName, Minify: true})
					}
				}
			}
			fileName := jf.fileName() + ext
			if _, ok := concatFileCache[fileName]; ok {
				return "/" + ext[1:] + "/" + fileName
			}
			if err := jf.concat(filepath.Join(staticPath, ext[1:], fileName), currentPath); err != nil {
				fmt.Println(src)
				core.LOG.Panic(err)
			}
			concatFileCache[fileName] = true
			return "/" + ext[1:] + "/" + fileName
		},
	}).Parse(string(bys))
	if err != nil {
		return err
	}
	out, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer out.Close()
	if err = t.Execute(out, nil); err != nil {
		fmt.Println(src, err)
	}
	return err

}
