#ifndef VFS_VFS_H_
#define VFS_VFS_H_

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "spinlock/spinlock.h"
#include "fs/portlfs/portlfs.h"
#include "storedev/storedev.h"
#include "sysdefs/fs.h"
#include "compiler/attr.h"

#define VFS_MOUNTPOINT_LABEL_MAX 128
#define VFS_MOUNTPOINTS_MAX 30

enum {
  VFS_LITTLEFS,
};

UNUSED static const char *vfs_strings[] = {
  "Little FS",
};

enum {
  VFS_FLAG_READ   = 1<<0,
  VFS_FLAG_WRITE  = 1<<1,
  VFS_FLAG_MAKE   = 1<<2,
};

#define VFS_PATH_MAX 1024

typedef struct VfsObj {
  SpinLock spinlock;
  void *extra;
  size_t extrasize;
  struct VfsMountPoint *vmp;
  char path[VFS_PATH_MAX];
  int32_t flags;
  int32_t (*read)(struct VfsObj *vobj, uint8_t *const buffer, size_t n, size_t off);
  int32_t (*write)(struct VfsObj *vobj, const uint8_t *const buffer, size_t n, size_t off);
  void (*cleanup)(struct VfsObj *vobj);
} VfsObj;

typedef struct VfsMountPoint {
  int _hshtbstate;
  char label[VFS_MOUNTPOINT_LABEL_MAX];

  int32_t fstype;
  StoreDev *backingsd;

  VfsObj *(*open)(struct VfsMountPoint *vmp, const char *path, uint32_t flags);
  int32_t (*cleanup)(struct VfsMountPoint *vmp);
  int32_t (*stat)(struct VfsMountPoint *vmp, const char *path, FsStat *statbuf);
  int32_t (*fetchdirent)(struct VfsMountPoint *vmp, const char *path, FsDirent *direntbuf, size_t idx);
  int32_t (*mkdir)(struct VfsMountPoint *vmp, const char *path);
  int32_t (*delete)(struct VfsMountPoint *vmp, const char *path);

  union {
    LittleFs littlefs;
  } fs;
  SpinLock spinlock;
} VfsMountPoint;

typedef struct {
  SpinLock spinlock;
  VfsMountPoint mountpoints[VFS_MOUNTPOINTS_MAX];
} VfsTable;

extern VfsTable VFS_TABLE;

void vfs_init(void);
int32_t vfs_unmount(char *mountpoint);
int32_t vfs_mount(char *mountpoint, int32_t fstype, StoreDev *backingsd, bool format);
void vfs_close(VfsObj *vobj);
VfsObj *vfs_open(char *mountpoint, const char *path, uint32_t flags);
int32_t vfs_stat(char *mountpoint, const char *path, FsStat *stat);
int32_t vfs_fetchdirent(char *mountpoint, const char *path, FsDirent *direntbuf, size_t idx);
int32_t vfs_mkdir(char *mountpoint, const char *path);
int32_t vfs_delete(char *mountpoint, const char *path);

#endif // VFS_VFS_H_
