/*********************************************************************
 * This file is part of the cpplibs suite.
 *
 * Copyright (C) 2001 Topi Mäenpää
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.6 $
 *********************************************************************/

#ifndef _IO_FILE_H
#define _IO_FILE_H

#include <sys/stat.h>
#include <string>

#include "../List.h"
#include "../Blob.h"
#include "IO.h"

namespace util { namespace io {
	/**
	 * The File class contains static methods for various
	 * filesystem-related purposes.
	 **/
	class File
	{
	public:
		/**
		 * Create a directory.
		 *
		 * @param path the name of the directory
		 * @param mode the mode of the file
		 * @see #chmod(string, mode_t)
		 **/
		static void mkdir(std::string path, mode_t mode) throw (IOException&);
		/**
		 * Remove a file or directory.
		 **/
		static void remove(std::string path) throw (IOException&);
		/**
		 * Rename a file. A file can be "renamed" to another directory,
		 * effectively performing a "move" operation.
		 **/
		static void rename(std::string oldName, std::string newName) throw (IOException&);
		/**
		 * Change the mode of a file. The mode of a file is most easily
		 * formed by a logical OR operation of some of the following:
		 * <table border=0>
		 * <tr><td><b>Constant</b></td><td><b>Value</b></td><td></b>Description</b></td></tr>
		 * <tr><td>S_ISUID</td><td>04000</td><td>Set user ID on execution.</td></tr>
		 * <tr><td>S_ISGID</td><td>020#0</td><td>Set group ID on execution if # is 7,
		 * 5, 3, or 1.<br>Enable mandatory file/record locking if # is 6, 4, 2, or 0.</td></tr>
		 * <tr><td>S_ISVTX</td><td>01000</td><td>Save text image  after execution.</td></tr>
		 * <tr><td>S_IRWXU</td><td>00700</td><td>Read, write, execute by owner.</td></tr>
		 * <tr><td>S_IRUSR</td><td>00400</td><td>Read by owner.</td></tr>
		 * <tr><td>S_IWUSR</td><td>00200</td><td>Write by owner.</td></tr>
		 * <tr><td>S_IXUSR</td><td>00100</td><td>Execute (search if a directory) by owner.</td></tr>
		 * <tr><td>S_IRWXG</td><td>00070</td><td>Read, write, execute by group.</td></tr>
		 * <tr><td>S_IRGRP</td><td>00040</td><td>Read by group.</td></tr>
		 * <tr><td>S_IWGRP</td><td>00020</td><td>Write by group.</td></tr>
		 * <tr><td>S_IXGRP</td><td>00010</td><td>Execute by group.</td></tr>
		 * <tr><td>S_IRWXO</td><td>00007</td><td>Read, write, execute (search) by others.</td></tr>
		 * <tr><td>S_IROTH</td><td>00004</td><td>Read by others.</td></tr>
		 * <tr><td>S_IWOTH</td><td>00002</td><td>Write by others.</td></tr>
		 * <tr><td>S_IXOTH</td><td>00001</td><td>Execute by others.</td></tr>
		 * </table>
		 * <p>
		 *
		 * For example, chmod("foo.bar",S_IRUSR | S_IWUSR) sets read and
		 * write permissions to the owner of file "foo.bar".
		 **/
		static void chmod(std::string path, mode_t mode) throw (IOException&);
		/**
		 * Get the mode of a file.
		 *
		 * @see #chmod(string, mode_t)
		 **/
		static mode_t getMode(std::string path) throw (IOException&);

		/**
		 * Check if the file denoted by <i>path</i> is a directory.
		 **/
		static bool isDirectory(std::string path) throw (IOException&) { return (bool)S_ISDIR(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a regular file.
		 **/
		static bool isFile(std::string path) throw (IOException&) { return (bool)S_ISREG(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a character device.
		 **/
		static bool isCharDevice(std::string path) throw (IOException&) { return (bool)S_ISCHR(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a block device.
		 **/
		static bool isBlockDevice(std::string path) throw (IOException&) { return (bool)S_ISBLK(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a FIFO.
		 **/
		static bool isFifo(std::string path) throw (IOException&) { return (bool)S_ISFIFO(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a symbolic link.
		 **/
		static bool isLink(std::string path) throw (IOException&) { return (bool)S_ISLNK(getMode(path)); }
		/**
		 * Check if the file denoted by <i>path</i> is a socket.
		 **/
		static bool isSocket(std::string path) throw (IOException&) { return (bool)S_ISSOCK(getMode(path)); }
		
		/**
		 * Change the owner of a file.
		 **/
		static void chown(std::string path, std::string owner) throw (IOException&);
		/**
		 * Change the group of a file.
		 **/
		static void chgrp(std::string path, std::string group) throw (IOException&);
		/**
		 * Check if a file exists.
		 **/
		static bool exists(std::string path) throw (IOException&);
		/**
		 * Get the size of a file in bytes. In many cases, it is useful to
		 * cast the returned value to an int.
		 **/
		static off_t getSize(std::string path) throw (IOException&);
		/**
		 * Get the number of hard links that point to a file.
		 **/
		static nlink_t getLinks(std::string path) throw (IOException&);

		/**
		 * Get the name of the owner of a file.
		 **/
		static std::string getOwner(std::string path) throw (IOException&);
		/**
		 * Get the name of the group of a file.
		 **/
		static std::string getGroup(std::string path) throw (IOException&);
		/**
		 * Get the ID of the owner of a file.
		 **/
		static uid_t getOwnerID(std::string path) throw (IOException&);
		/**
		 * Get the ID of the group of a file.
		 **/
		static gid_t getGroupID(std::string path) throw (IOException&);

		/**
		 * Get the time of the last access to a file.
		 **/
		static time_t getAccessTime(std::string path) throw (IOException&);
		/**
		 * Get the time of the last modification of a file stats.
		 **/
		static time_t getChangeTime(std::string path) throw (IOException&);
		/**
		 * Get the time of the last change to the contents of a file.
		 **/
		static time_t getModificationTime(std::string path) throw (IOException&);

		/**
		 * Get the base name of a path. See basename(3) for details.
		 **/
		static std::string baseName(std::string path);
		/**
		 * Get the directory name of a path. See basename(3) for details.
		 **/
		static std::string dirName(std::string path);

		/**
		 * Change current working directory.
		 **/
		static void setWorkDir(std::string path) throw (IOException&);
		/**
		 * Get current working directory.
		 **/
		static std::string getWorkDir() throw (IOException&);
		
		/**
		 * Return the names of files in a directory. Use the blockSize
		 * parameter to adjust the performance of the method. Larger
		 * blockSize means more memory is initially allocated to store the
		 * directory entries.
		 **/
		static List<std::string> listDir(std::string path, int blockSize=128) throw (IOException&);

		/**
		 * Return the names of files matching a wildcard pattern. The
		 * pattern may contain any familiar shell wild cards. Examples:
		 *
		 * <pre>
		 * File::wildCard("*.cc"); //matches files with a .cc suffix
		 * File::wildCard("[fbx-z]*.txt"); //matches foo.txt, bar.txt, x1.txt etc.
		 * File::wildCard("/home/me/code.{cc,h}"); //matches code.cc and code.h
		 * </pre>
		 **/
		static List<std::string> wildCard(std::string pattern) throw (IOException&);

		/**
		 * Read the contents of a file as a string.
		 **/
		static std::string readContents(std::string file) throw (IOException&);
		/**
		 * Read the contents of a file as a Blob. The pointer stored into
		 * the returned blob is allocated with malloc(), and must be
		 * released by the caller.
		 **/
		static util::Blob<char> readBlob(std::string file) throw (IOException&);

		/**
		 * Read the lines of a text file as a list of strings. Use the
		 * blockSize parameter to adjust the performance of the method. 
		 * Use a large value for large files.
		 **/
		static List<std::string> readLines(std::string file, int blockSize=128) throw (IOException&);

	private:
		static std::string getErrorString(int error);
	};
}}

#endif
