#pragma once

#include "IFilesystem.h"
#include "fs/Error.h"
#include "fs/Mode.h"
#include "fs/Api.h"
#include "tl/vector.h"

namespace fs
{
class FS_API NativeFilesystem final : public IFilesystem, public tl::lendable_base<NativeFilesystem>
{
public:

	enum class CheckFlag : uint8_t
	{
		ValidatePathCase, //Win32 only, relatively slow, but makes the filesystem behave more like on posix (case-sensitive filenames)
	};
	using CheckFlags = tl::flag_set2<CheckFlag>;

	NativeFilesystem() = default;
	explicit NativeFilesystem(CheckFlags checkFlags);

	OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
	OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
	OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
	OpenSinkResult openSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
	OpenStreamSinkResult openStreamSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
	OpenMapSinkResult openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) override;

	ConvertToNativePathResult convertToNativePath(AbsPathView path) const override;

	IsFileResult isFile(AbsPathView path) const override;
	IsFolderResult isFolder(AbsPathView path) const override;
	ExistsResult exists(AbsPathView path) const override;

	MakeFolderResult makeFolder(AbsPathView path) override;

	RenameResult rename(AbsPathView path, AbsPathView newPath) override;

	RemoveResult remove(AbsPathView path) override;
	RemoveRecursivelyResult removeRecursively(AbsPathView path) override;

	CopyResult copy(AbsPathView path, AbsPathView newPath) override;

	MakeHardLinkResult makeHardLink(AbsPathView sourcePath, AbsPathView linkPath) override;
	MakeSoftLinkResult makeSymLink(AbsPathView sourcePath, AbsPathView linkPath) override;

	SetWriteTimeResult setWriteTime(AbsPathView path, time_t time) override;

	GetStatResult getStat(AbsPathView path) const override;

	cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const override;
	cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const override;

	AbsPath getCurrentFolder() const;
	tl::result<Error> setCurrentFolder(AbsPathView path);

	typedef tl::result<tl::vector<tl::string>, Error> EnumerateFilesResult;
	EnumerateFilesResult enumerateFiles(AbsPathView fullPath) const;

	typedef tl::result<tl::vector<tl::string>, Error> EnumerateFoldersResult;
	EnumerateFoldersResult enumerateFolders(AbsPathView fullPath) const;

	AbsPath makeAbsPath(const tl::string& string) const;
	

private:
	CheckFlags m_checkFlags;
};

//this FS will do various checks to make the platforms behave similarly
//For example path case checks on Win32 to make its FS case-sensitive
FS_API extern NativeFilesystem native;

//this FS is RAW with no advanced (read: slow) checks
//Use it where appropriate, where native is clearly slowing down something vital.
//Normal use-case: tools
//*** For game or library use, consult with the lead, and think 3 times. ***
FS_API extern NativeFilesystem nativeRaw;

}
