/*! \file pidir.h
 * \ingroup IO
 * \~\brief
 * \~english Local directory
 * \~russian Локальная директория
 */
/*
    PIP - Platform Independent Primitives
    Directory
    Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PIDIR_H
#define PIDIR_H

#include "pifile.h"
#include "piregularexpression.h"


//! \~\ingroup IO
//! \~\brief
//! \~english Local directory.
//! \~russian Локальная директория.
class PIP_EXPORT PIDir {
public:
	//! \~english Constructs directory with path "dir".
	//! \~russian Создает директорию с путём "dir".
	PIDir(const PIString & dir = PIString());

	//! \~english Constructs directory with "file" directory path.
	//! \~russian Создает директорию с путём директории файла "file".
	PIDir(const PIFile & file);


	//! \~english Returns if this directory exists.
	//! \~russian Возвращает, существует ли эта директория.
	bool isExists() const { return PIDir::isExists(path()); }

	//! \~english Returns if path of this directory is absolute.
	//! \~russian Возвращает, абсолютный ли путь у директории.
	bool isAbsolute() const;

	//! \~english Returns if path of this directory is relative.
	//! \~russian Возвращает, относительный ли путь у директории.
	bool isRelative() const { return !isAbsolute(); }

	//! \~english Returns path of current reading directory. This path valid only while \a allEntries() functions.
	//! \~russian Возвращает путь текущей директории чтения. Этот путь действителен только во время выполнения метода \a allEntries().
	const PIString & scanDir() const { return scan_; }


	//! \~english Returns name of this directory.
	//! \~russian Возвращает имя директории.
	PIString name() const;

	//! \~english Returns path of this directory.
	//! \~russian Возвращает путь директории.
	PIString path() const;

	//! \~english Returns absolute path of this directory.
	//! \~russian Возвращает абсолютный путь директории.
	PIString absolutePath() const;

	//! \~english Simplify path of this directory.
	//! \~russian Упрощает путь директории.
	PIDir & cleanPath();

	//! \~english Returns %PIDir with simplified path of this directory.
	//! \~russian Возвращает %PIDir с упрощённым путём директории.
	PIDir cleanedPath() const {
		PIDir d(path());
		d.cleanPath();
		return d;
	}

	//! \~english Returns relative to this directory path "path".
	//! \~russian Возвращает путь "path" относительно этой директории.
	PIString relative(const PIString & path) const;

	//! \~english Returns relative to this directory path "path" as absolute path.
	//! \~russian Возвращает путь "path" относительно этой директории в виде абсолютного пути.
	PIString absolute(const PIString & path) const;

	//! \~english Set this directory path to simplified "path".
	//! \~russian Устанавливает путь директории упрощённым "path".
	PIDir & setDir(const PIString & path);

	//! \~english Set this directory path as current for application.
	//! \~russian Устанавливает путь директории текущим путём приложения.
	bool setCurrent() { return PIDir::setCurrent(path()); }


	//! \~english Returns this directory content.
	//! \~russian Возвращает содержимое этой директории.
	PIVector<PIFile::FileInfo> entries(const PIRegularExpression & regexp = {});

	//! \~english Returns this directory content recursively.
	//! \~russian Возвращает содержимое этой директории рекурсивно.
	PIVector<PIFile::FileInfo> allEntries(const PIRegularExpression & regexp = {});

	//! \~english Make this directory, recursively if "withParents".
	//! \~russian Создаёт эту директорию, рекурсивно если "withParents".
	bool make(bool withParents = true);

	//! \~english Remove this directory.
	//! \~russian Удаляет эту директорию.
	bool remove() { return PIDir::remove(path()); }

	//! \~english Rename this directory.
	//! \~russian Переименовывает эту директорию.
	bool rename(const PIString & new_name);

	//! \~english Change this directory to relative path "path".
	//! \~russian Изменяет директорию на относительный путь "path".
	PIDir & cd(const PIString & path);

	//! \~english Change this directory to parent.
	//! \~russian Изменяет директорию на родительскую.
	PIDir & up() { return cd(".."); }

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	bool operator==(const PIDir & d) const;

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	bool operator!=(const PIDir & d) const { return !((*this) == d); }

	static const PIChar separator;


	//! \~english Returns current directory for application.
	//! \~russian Возвращает текущую директорию приложения.
	static PIDir current();

	//! \~english Returns user home directory.
	//! \~russian Возвращает домашнюю директорию пользователя.
	static PIDir home();

	//! \~english Returns temporary directory.
	//! \~russian Возвращает временную директорию.
	static PIDir temporary();

	//! \~english Returns directory "path" content recursively.
	//! \~russian Возвращает содержимое директории "path" рекурсивно.
	static PIVector<PIFile::FileInfo> allEntries(const PIString & path, const PIRegularExpression & regexp = {});

	//! \~english Returns if directory "path" exists.
	//! \~russian Возвращает, существует ли эта директория.
	static bool isExists(const PIString & path);

	//! \~english Make directory "path", recursively if "withParents".
	//! \~russian Создаёт директорию "path", рекурсивно если "withParents".
	static bool make(const PIString & path, bool withParents = true);

	//! \~english Remove directory "path".
	//! \~russian Удаляет директорию "path".
	static bool remove(const PIString & path) { return removeDir(path); }

	//! \~english Rename directory "path".
	//! \~russian Переименовывает директорию "path".
	static bool rename(const PIString & path, const PIString & new_name) { return PIDir::renameDir(path, new_name); }

	//! \~english Set path "path" as current for application.
	//! \~russian Устанавливает путь "path" текущим путём приложения.
	static bool setCurrent(const PIString & path);

	//! \~english Set directory "dir" path as current for application.
	//! \~russian Устанавливает путь директории "dir" текущим путём приложения.
	static bool setCurrent(const PIDir & dir) { return setCurrent(dir.path()); }


	//! \~\ingroup IO
	//! \~\brief
	//! \~english Temporarily change working directory.
	//! \~russian Временная смена рабочей директории.
	class PIP_EXPORT CurrentDirOverrider {
	public:
		//! \~english Change working directory dir or file with relative or absolute path "path".
		//! \~russian Меняет рабочую директорию на другую директорию или файл с относительным или абсолютным путём "path".
		CurrentDirOverrider(const PIString & path);

		//! \~english Change working directory to dir or file "info".
		//! \~russian Меняет рабочую директорию на директорию или файл "info".
		CurrentDirOverrider(const PIFile::FileInfo & info);

		~CurrentDirOverrider() { restore(); }

		//! \~english Restore previous working directory.
		//! \~russian Восстанавливает предыдущую рабочую директорию.
		void restore();

	private:
		void save(const PIFile::FileInfo & info);
		PIString prev_cd;
		bool active = true;
	};


private:
	static bool makeDir(const PIString & path);
	static bool removeDir(const PIString & path);
	static bool renameDir(const PIString & path, const PIString & new_name);

	PIString path_, scan_;
};


inline bool operator<(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
	return (v0.path < v1.path);
}
inline bool operator>(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
	return (v0.path > v1.path);
}
inline bool operator==(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
	return (v0.path == v1.path);
}
inline bool operator!=(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
	return (v0.path != v1.path);
}


//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator<<(PICout s, const PIDir & v) {
	s.saveAndSetControls(0);
	s << "PIDir(\"" << v.path() << "\")";
	s.restoreControls();
	return s;
}


#endif // PIDIR_H
