//
// File.h
//
// Library: Foundation
// Package: Filesystem
// Module:  File
//
// Definition of the File class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#ifndef Foundation_File_INCLUDED
#define Foundation_File_INCLUDED


#include "Poco/Foundation.h"
#include "Poco/Timestamp.h"
#include <vector>


#if defined(POCO_OS_FAMILY_WINDOWS)
#include "Poco/File_WIN32U.h"
#elif defined(POCO_VXWORKS)
#include "Poco/File_VX.h"
#elif defined(POCO_OS_FAMILY_UNIX)
#include "Poco/File_UNIX.h"
#endif


namespace Poco {


class Path;


class Foundation_API File: private FileImpl
	/// The File class provides methods for working with a file.
	///
	/// Regarding paths passed to the various methods, note that
	/// platform-specific limitations regarding maximum length
	/// of the entire path and its components apply.
	///
	/// On Windows, the implementation tries to work around the rather low
	/// 260 characters MAX_PATH limit by adding the "\\?\" prefix if
	/// a path is absolute and exceeds MAX_PATH characters in length.
	/// Note that various limitations regarding usage of the "\\?\"
	/// prefix apply in that case, e.g. the path must
	/// not contain relative components ("." and "..") and must not
	/// use the forward slash ("/") as directory separator.
{
public:
	using FileSize = FileSizeImpl;

	enum LinkType
		/// Type of link for linkTo().
	{
		LINK_HARD     = 0, /// hard link
		LINK_SYMBOLIC = 1  /// symbolic link
	};

	enum Options
		/// Options for File Copy/Movement
	{
		OPT_FAIL_ON_OVERWRITE = OPT_FAIL_ON_OVERWRITE_IMPL
	};

	File();
		/// Creates the file.

	File(const std::string& path);
		/// Creates the file.

	File(const char* path);
		/// Creates the file.

	File(const Path& path);
		/// Creates the file.

	File(const File& file);
		/// Copy constructor.

	~File() override;
		/// Destroys the file.

	File& operator = (const File& file);
		/// Assignment operator.

	File& operator = (const std::string& path);
		/// Assignment operator.

	File& operator = (const char* path);
		/// Assignment operator.

	File& operator = (const Path& path);
		/// Assignment operator.

	void swap(File& file) noexcept;
		/// Swaps the file with another one.

	const std::string& path() const;
		/// Returns the path.

	std::string absolutePath() const;
		/// Returns the absolute path.
		///
		/// If the path is already absolute, returns it unchanged.
		/// If the path is relative, resolves it against the
		/// current working directory.

	std::string getExecutablePath() const;
		/// Resolves the executable path.
		///
		/// If the path contains a directory separator, checks whether
		/// it exists and is executable, resolves it to an absolute
		/// path and returns it.
		///
		/// If the path is a bare filename (no directory separator),
		/// searches the current directory and the PATH environment
		/// variable for an executable match.
		///
		/// On Windows, also tries appending each PATHEXT extension
		/// (e.g. .EXE, .CMD, .BAT) if the bare filename is not
		/// found as-is.
		///
		/// Returns the fully resolved absolute path on success,
		/// or an empty string if no executable was found.
		///
		/// Known limitation on Windows: If the PATH environment variable
		/// contains UNC paths (e.g., \\server\share\bin), SearchPathW may
		/// not find executables in those locations when searching for bare
		/// filenames. This is a Windows API limitation, not a Poco limitation.
		/// Workaround: Use the full UNC path including the executable name.

	bool exists() const;
		/// Returns true iff the file exists.

	bool existsAnywhere() const;
		/// Returns true iff the file exists anywhere in the
		/// file system, including in directories listed in
		/// the PATH environment variable.

	bool canRead() const;
		/// Returns true iff the file is readable.

	bool canWrite() const;
		/// Returns true iff the file is writeable.

	bool canExecute() const;
		/// Returns true iff the file is executable.
		///
		/// Resolves the executable path using getExecutablePath().
		/// If the resolved path is empty, returns false.

	bool isFile() const;
		/// Returns true iff the file is a regular file.

	bool isLink() const;
		/// Returns true iff the file is a symbolic link.

	bool isDirectory() const;
		/// Returns true iff the file is a directory.

	bool isDevice() const;
		/// Returns true iff the file is a device.

	bool isHidden() const;
		/// Returns true if the file is hidden.
		///
		/// On Windows platforms, the file's hidden
		/// attribute is set for this to be true.
		///
		/// On Unix platforms, the file name must
		/// begin with a period for this to be true.

	Timestamp created() const;
		/// Returns the creation date of the file.
		///
		/// Not all platforms or filesystems (e.g. Linux and most Unix
		/// platforms with the exception of FreeBSD and Mac OS X)
		/// maintain the creation date of a file.
		/// On such platforms, created() returns
		/// the time of the last inode modification.

	Timestamp getLastModified() const;
		/// Returns the modification date of the file.

	File& setLastModified(const Timestamp& ts);
		/// Sets the modification date of the file.

	FileSize getSize() const;
		/// Returns the size of the file in bytes.

	File& setSize(FileSize size);
		/// Sets the size of the file in bytes. Can be used
		/// to truncate a file.

	File& setWriteable(bool flag = true);
		/// Makes the file writeable (if flag is true), or
		/// non-writeable (if flag is false) by setting the
		/// file's flags in the filesystem accordingly.

	File& setReadOnly(bool flag = true);
		/// Makes the file non-writeable (if flag is true), or
		/// writeable (if flag is false) by setting the
		/// file's flags in the filesystem accordingly.

	File& setExecutable(bool flag = true);
		/// Makes the file executable (if flag is true), or
		/// non-executable (if flag is false) by setting
		/// the file's permission bits accordingly.
		///
		/// Does nothing on Windows.

	void copyTo(const std::string& path, int options = 0) const;
		/// Copies the file (or directory) to the given path.
		/// The target path can be a directory.
		///
		/// A directory is copied recursively.
		/// If options is set to OPT_FAIL_ON_OVERWRITE the method throws a FileExistsException
		/// if the File already exists.

	void moveTo(const std::string& path, int options = 0);
		/// Copies the file (or directory) to the given path and
		/// removes the original file. The target path can be a directory.
		/// If options is set to OPT_FAIL_ON_OVERWRITE the method throws a FileExistsException
		/// if the File already exists.

	void renameTo(const std::string& path, int options = 0);
		/// Renames the file to the new name.
		/// If options is set to OPT_FAIL_ON_OVERWRITE the method throws a FileExistsException
		/// if the File already exists.

	void linkTo(const std::string& path, LinkType type = LINK_SYMBOLIC) const;
		/// Creates a link (symbolic or hard, depending on type argument)
		/// at the given path to the file or directory.
		///
		/// May not be supported on all platforms.
		/// Furthermore, some operating systems do not allow creating
		/// hard links to directories.

	void remove(bool recursive = false);
		/// Deletes the file. If recursive is true and the
		/// file is a directory, recursively deletes all
		/// files in the directory.

	bool createFile();
		/// Creates a new, empty file in an atomic operation.
		/// Returns true if the file has been created and false
		/// if the file already exists. Throws an exception if
		/// an error occurs.

	bool createDirectory();
		/// Creates a directory. Returns true if the directory
		/// has been created and false if it already exists.
		/// Throws an exception if an error occurs.

	void createDirectories();
		/// Creates a directory (and all parent directories
		/// if necessary).

	void list(std::vector<std::string>& files) const;
		/// Fills the vector with the names of all
		/// files in the directory.

	void list(std::vector<File>& files) const;
		/// Fills the vector with the names of all
		/// files in the directory.

	FileSize totalSpace() const;
		/// Returns the total size in bytes of the partition containing this path.

	FileSize usableSpace() const;
		/// Returns the number of usable free bytes on the partition containing this path.

	FileSize freeSpace() const;
		/// Returns the number of free bytes on the partition containing this path.

	bool operator == (const File& file) const;
	bool operator != (const File& file) const;
	bool operator <  (const File& file) const;
	bool operator <= (const File& file) const;
	bool operator >  (const File& file) const;
	bool operator >= (const File& file) const;

	static void handleLastError(const std::string& path);
		/// For internal use only. Throws an appropriate
		/// exception for the last file-related error.

protected:
	void copyDirectory(const std::string& path, int options = 0) const;
		/// Copies a directory. Used internally by copyTo().
};


//
// inlines
//
inline const std::string& File::path() const
{
	return getPathImpl();
}


inline bool File::operator == (const File& file) const
{
	return getPathImpl() == file.getPathImpl();
}


inline bool File::operator != (const File& file) const
{
	return getPathImpl() != file.getPathImpl();
}


inline bool File::operator < (const File& file) const
{
	return getPathImpl() < file.getPathImpl();
}


inline bool File::operator <= (const File& file) const
{
	return getPathImpl() <= file.getPathImpl();
}


inline bool File::operator > (const File& file) const
{
	return getPathImpl() > file.getPathImpl();
}


inline bool File::operator >= (const File& file) const
{
	return getPathImpl() >= file.getPathImpl();
}


inline void swap(File& f1, File& f2) noexcept
{
	f1.swap(f2);
}


} // namespace Poco


#endif // Foundation_File_INCLUDED
