//go:build windows

package yu_file

import (
	yu_math "gogs.qqck.cn/s/tools/math"
	yu_sys "gogs.qqck.cn/s/tools/sys"
	"strings"
	"syscall"
	"unsafe"
)

// MkDirs
//
//	@Description: 创建多级目录，必须为绝对路径。
func MkDirs(path string) bool {
	j_code := yu_sys.SHCreateDirectoryExW.CallUintptr(0, yu_sys.S{yu_sys.Unicode, path}, 0)
	return j_code == 0 || j_code == yu_sys.ERROR_FILE_EXISTS || j_code == yu_sys.ERROR_ALREADY_EXISTS
}

// Find
//
//	@Description: 基础对象
type Find struct {
	// Path 欲搜索的目录
	Path string

	// Name 欲匹配的文件名，默认为"*"所有，"?"匹配一个任意的字符，"*"匹配无限个任意的字符，包括没有字符，可以组合使用，默认：*
	Name string

	// Type 0：文件及目录，1：文件、2：目录，默认：0
	Type byte

	// Start 起始位置，默认：0
	Start int

	// Count 记录数量，-1为所有，默认：-1
	Count int

	// Son 是否遍历子目录，默认：false
	Son bool

	// AddPath 返回结果是否为全路径，默认：false
	AddPath bool
}

// NewFind
//
//	@Description: 创建 Find 操作对象
func NewFind() (t *Find) {
	t = new(Find)
	t.SetName("*")
	t.SetCount(-1)
	return
}

// SetPath
//
//	@Description: 设置操作路径
func (t *Find) SetPath(path string) *Find {
	if t.Path = path; !strings.HasSuffix(t.Path, `\`) {
		t.Path += `\`
	}
	return t
}

// SetName
//
//	@Description: 欲匹配的文件名，默认为"*"所有，"?"匹配一个任意的字符，"*"匹配无限个任意的字符，包括没有字符，可以组合使用，默认：*
func (t *Find) SetName(name string) *Find {
	t.Name = name
	return t
}

// SetType
//
//	@Description: 0：文件及目录，1：文件、2：目录，默认：0
func (t *Find) SetType(Type byte) *Find {
	t.Type = Type
	return t
}

// SetStart
//
//	@Description: 起始位置，默认：0
func (t *Find) SetStart(Start int) *Find {
	t.Start = Start
	return t
}

// SetCount
//
//	@Description: 记录数量，-1为所有，默认：-1
func (t *Find) SetCount(Count int) *Find {
	if Count < 0 {
		t.Count = yu_math.MaxInt
	} else {
		t.Count = Count
	}
	return t
}

// SetSon
//
//	@Description: 是否遍历子目录，默认：false
func (t *Find) SetSon(Son bool) *Find {
	t.Son = Son
	return t
}

// SetAddPath
//
//	@Description: 返回结果是否为全路径，默认：false
func (t *Find) SetAddPath(AddPath bool) *Find {
	t.AddPath = AddPath
	return t
}

// Enum
//
//	@Description: 寻找文件
func (t *Find) Enum() []string {
	return t.findEnum(t.Path, t.Name, "", t.Start, t.Count)
}

func (t *Find) findEnum(path, name, parent string, start, count int) []string {
	j_fileinfo := &yu_sys.FindData{}
	j_handle := yu_sys.FindFirstFileW.CallInt(yu_sys.S{yu_sys.Unicode, path + name}, unsafe.Pointer(j_fileinfo))
	if j_handle == -1 {
		return nil
	}
	defer yu_sys.FindClose.Call(j_handle)
	var j_list []string
	for {
		if j_filename := unicode_utf8(j_fileinfo.FileName); j_filename != "." && j_filename != ".." {
			if (t.Type == 0) || // 文件及目录
				(t.Type == 1 && j_fileinfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0) || // 文件
				(t.Type == 2 && j_fileinfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0) { // 目录
				if start > 0 {
					start--
				} else if count > 0 {
					count--
					if t.AddPath {
						j_list = append(j_list, path+j_filename)
					} else {
						j_list = append(j_list, parent+j_filename)
					}
				} else {
					break
				}
			}
			if t.Son && j_fileinfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
				j_list = append(j_list, t.findEnum(path+j_filename+"\\", name, parent+j_filename+"\\", start, count)...)
			}
		}
		if !yu_sys.FindNextFileW.CallBool(j_handle, unsafe.Pointer(j_fileinfo)) {
			break
		}
	}
	return j_list
}

func unicode_utf8(unicode [520]byte) string {
	j_utf8_size := yu_sys.WideCharToMultiByte.CallInt(65001, 0, unicode[:], -1, 0, 0, 0, 0) * 3
	j_utf8 := make([]byte, j_utf8_size)
	return string(j_utf8[:yu_sys.WideCharToMultiByte.CallInt(65001, 0, unicode[:], -1, j_utf8, j_utf8_size, 0, 0)-1])
}
