//go:build linux || (darwin && amd64)

package fuse

import (
	"io"
	"os"
	"time"
)

// 目录从设计上来说不需要打开操作，所以dirHandle就是fusefs的DirHandle接口的完整实现。
type dirHandle struct {
	dir       FsDir
	dirReader DirReader
}

func newDirHandle(dir FsDir, dirReader DirReader) *dirHandle {
	return &dirHandle{dir: dir, dirReader: dirReader}
}

// Readdir reads the contents of the directory associated with file and returns
// a slice of up to n FileInfo values, as would be returned by Lstat, in
// directory order. Subsequent calls on the same file will yield further
// FileInfos.
//
// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
// Readdir returns an empty slice, it will return a non-nil error explaining
// why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdir returns all the FileInfo from the directory in a single
// slice. In this case, if Readdir succeeds (reads all the way to the end of
// the directory), it returns the slice and a nil error. If it encounters an
// error before the end of the directory, Readdir returns the FileInfo read
// until that point and a non-nil error.
func (fh *dirHandle) Readdir(n int) (fis []os.FileInfo, err error) {
	entries, err := fh.dirReader.Next(n)
	if err != nil {
		return nil, err
	}

	if len(entries) == 0 {
		return nil, io.EOF
	}

	var infos []os.FileInfo
	for _, entry := range entries {
		infos = append(infos, &fileInfo{entry})
	}

	return infos, nil
}

// Readdirnames reads and returns a slice of names from the directory f.
//
// If n > 0, Readdirnames returns at most n names. In this case, if
// Readdirnames returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdirnames returns all the names from the directory in a single
// slice. In this case, if Readdirnames succeeds (reads all the way to the end
// of the directory), it returns the slice and a nil error. If it encounters an
// error before the end of the directory, Readdirnames returns the names read
// until that point and a non-nil error.
func (fh *dirHandle) Readdirnames(n int) (names []string, err error) {
	entries, err := fh.dirReader.Next(n)
	if err != nil {
		return nil, err
	}

	if len(entries) == 0 {
		return nil, io.EOF
	}

	for _, entry := range entries {
		names = append(names, entry.Name())
	}

	return names, nil
}

// Close closes the handle
func (fh *dirHandle) Close() (err error) {
	fh.dirReader.Close()
	return nil
}

type fileInfo struct {
	entry FsEntry
}

func (fi *fileInfo) Name() string {
	return fi.entry.Name()
}

func (fi *fileInfo) Size() int64 {
	return fi.entry.Size()
}

func (fi *fileInfo) Mode() os.FileMode {
	if fi.entry.IsDir() {
		return os.ModeDir | fi.entry.Perm()
	}

	return fi.entry.Perm()
}

// ModTime returns the modification time of the file
func (fi *fileInfo) ModTime() time.Time {
	return fi.entry.ModTime()
}

func (fi *fileInfo) IsDir() bool {
	return fi.entry.IsDir()
}

func (fi *fileInfo) Sys() interface{} {
	return nil
}
