#ifndef	FSBASE_H
#define	FSBASE_H

#include <../source/TAL/objbase.h>
#include <../source/vfs/iobase.h>
#include <../source/vfs/mbase.h>

/*
 *	FIXME: make vfs thread - safe.
 *
 *	in vfsCreate(): vfs->vtbl.vfs_lock = mutexCreate();
 *
 *	in port::create()
 *		mutexLock(vol->vfs_lock);
 *		vol->base.ref_count++;
 *		mutexUnlock(vol->vfs_lock);
 *		port->volume = vol;
 *
 *	in port::destroy():
 *		mutexLock(port->volume->vfs_lock);
 *		port->volume->base.ref_count--;
 *		mutexUnlock(port->volume->vfs_lock);
 *
 *	The steps above turns on LibV handle protection, and, thus,
 *	vfs volume will not be unmounted while busy. Also note that
 *	we must NOT decrement ref_count in volume::destroy unless
 *	it equals to 1 (in later case volume isn't busy and can be
 *	safely unmounted).
 *
 *	We must perform locks/unlocks in vfsOpenDir / vfsCloseDir also,
 *	but there we must lock ENTIRE vfs tree.
 *
 */
 
/*
 *	Filesystem object
 */

typedef struct vfs_dev_s
{
	libv_object_t	base;
	mutex_t			vfs_lock; /* protects base.ref_count */
	char_p			(V_CALL *get_volume_name)(struct vfs_dev_s *self);
	u32_t			(V_CALL *get_inode_count)(struct vfs_dev_s *self);
	vboolean		(V_CALL *get_file_name)(struct vfs_dev_s *self,u32_t inode,char *name_ret);
	vhandle_t			(V_CALL *create_file)(struct vfs_dev_s *self,u32_t inode);
}	vfs_dev_t, *vfs_dev_p;

typedef struct vfs_mapped_port_s
{
	io_section_t	port;
	vfs_dev_t		*volume;
}	vfs_mapped_port_t, *vfs_mapped_port_p;

/*
 *	FS tree leaf: represent file
 */
typedef struct	vfs_leaf_s
{
	char		*name;				/* Only name of file, without path */
	vfs_dev_p	volume;				/* Filesystem of file */
	u32_t		inode;				/* Index of file in filesystem */
}	vfs_leaf_t, *vfs_leaf_p;

/*
 *	FS tree node (to store in <ntree_t*> -> data) - represent directory.
 */
typedef struct vfs_node_s
{
	char		*name;				/* Relative name of node */
	vp_stack_t	files;				/* Stack of vfs_leaf_t */
	/* List of all filesystems (used by vfsOpenDir()) */
	vp_stack_t	volumes;
}	vfs_node_t, *vfs_node_p;

/*
 *	Mode used by enumeration procedures.
 */
typedef enum
{
	vfs_mode_normal,
	vfs_mode_directory
}	vfs_mode_t;

/*
 *	Directory enumerator
 */
typedef struct vfs_enum_s
{
	/* private: */
	libv_object_t base;
	ntree_t		*node;
	char		node_path[_MAX_PATH];
	u32_t		num_nodes;
	u32_t		num_leafs;
	u32_t		node_num;
	u32_t		leaf_num;
	/* public: */
	vfs_dev_t	*vfs_dev;
	u32_t		vfs_ino;
	vfs_mode_t	vfs_mode;
	char		vfs_name[_MAX_PATH];
}	vfs_enum_t, *vfs_enum_p;

/*
 *	Mount procedure.
 *	Registered mount procedures will be called for every file
 *	by vfsInit().
 */
typedef vfs_dev_p	(V_CALL	*vfs_mount_proc_t)(char *volume_name);

#ifdef	__cplusplus
extern "C" {
#endif	/* __cplusplus */
	/*
	 * Creates filesystem object without any functionality.
	 */
	vfs_dev_p	V_CALL	vfsCreateFS(u32_t size_of_object);
	/*
	 * Closes vfs handle
	 */
	void	V_GLOBAL vfsDestroy(vhandle_t vfs_handle);
	/* Adds node to VFS tree. If 'path' is relative, it will be prepended
	 * with current (local) working directory; "." and ".." names in 'path' 
	 * also handled properly. */
	vboolean	V_CALL	vfsAddNode(ntree_p root,char *path,
		vfs_dev_t *volume,u32_t inode);
	/*
	 *	Searches for node in VFS tree.
	 */
	vboolean	V_CALL	vfsGetNodeData(ntree_p root,char *full_path,vfs_dev_t **volume_ret,u32_t *inode_ret);
	/*
	 *	Uses vfsGetNodeData() to obtain device and inode of 'path_name',
	 *	than calls dev->create_file(inode). Returns NULL on error.
	 */
	vhandle_t		V_CALL	vfsCreateFile(char *path_name);
	/*
	 *	Enumeration API's.
	 *	Normally, caller should use only 'vfs_name' field of
	 *	enumeration object.
	 */
	vfs_enum_p	V_CALL	vfsOpenDir(char *dir_name);
	vboolean	V_CALL	vfsReadDir(vfs_enum_p dir_enum);
	vboolean	V_CALL	vfsSeekDir(vfs_enum_p dir_enum,int offset,int whence);
	int			V_CALL	vfsTellDir(vfs_enum_p dir_enum);
	void		V_CALL	vfsCloseDir(vfs_enum_p dir_enum);
	void		V_CALL	vfsEnumFiles(char *vfs_path,
		void (V_CALL *dir_callback)(char *dir_name),
		void (V_CALL *file_callback)(char *file_name),
		vboolean recursive);
	void	V_CALL		vfsEnumFilesEx(char *vfs_path,
		void (V_CALL *dir_callback)(char *dir_name),
		void (V_CALL *file_callback)(char *file_name),
		vboolean recursive,
		vboolean show_hidden);
	/*
	 *	Adds filesystem factory to call from vfsInit()
	 */
	void		V_CALL	vfsRegisterMountProcedure(
		vfs_mount_proc_t mount_proc);
	/*
	 *		vfsInit() - searches for all local files starting from
	 *	current directory. Each file containing known file system mounted
	 *	at this local location; thus, vfs directory can contain files from
	 *	different file systems.
	 *		Currently, internally supported filesystems are:
	 *	- Id's PAK file system;
	 *	- EXE/DLL as resources (Win32 only, all compilers except WATCOM).
	 *	- old Id's WAD file system (see TODO in vfscat.c)
	 *	- zip/pk3 filesystem (probably, driver is buggy)
	 */
	void		V_CALL	vfsInit(void);
	/*
	 *	Empties VFS tree, unregisters all mount procedures.
	 */
	void		V_CALL	vfsShutdown(void);
#ifdef	__cplusplus
}
#endif	/* __cplusplus */

#endif	/* FSBASE_H */
