//
//  Copyright (c) 2015, 2016, 2018
//  by Mike Romberg ( mike-romberg@comcast.net )
//
//  This file may be distributed under terms of the GPL
//

//
// Utilities for dealing with files, direcoties, paths
// The idea is to make these similar to the nice os and os.path
// modules found in python.
//
#ifndef fsutil_h
#define fsutil_h

#include <string>
#include <vector>
#include <fstream>
#include <cstdint>  // for uint64_t for 32 bit systems



namespace util {

class fs {
public:
    // returns a list of names in the specified path (. and .. not included)
    static std::vector<std::string> listdir(const std::string &path);

    // returns true if path exists and is a directory
    static bool isdir(const std::string &path);

    // returns true if path exists and is a regular file
    static bool isfile(const std::string &path);

    // returns true if path exists and is a regular file and is executable
    static bool isexec(const std::string &path);

    // reads the entire file into str.  Returns false on failure.
    static bool readAll(const std::string &file, std::string &str);

    // errors to logBug or logFatal.
    static std::string readAll(const std::string &file, bool fatal=false);

    // reads the first X from file.  returns false on failure.
    template<class X>
    static bool readFirst(const std::string &file, X &x);

    // returns the current working directory as an absolute path
    static std::string cwd(void);


    // returns an absolute path to path
    static std::string abspath(const std::string &path);

    // collapse redundant separators and up-level references
    static std::string normpath(const std::string &path);

    // The absolute normalized path (canonical path)
    static std::string canonpath(const std::string &path) {
        return normpath(abspath(path));
    }

    // returns a canonical path to the command (using PATH if needed).
    // On failure, logs a problem (optional) and returns command.
    static std::string findCommand(const std::string &command, bool log=true);

    // maximum file name size for given file system
    static size_t fnameMax(const std::string &path);

    // returns first = bytes free, second = bytes total
    // path is any file or directory on the filesystem
    // if privileged is true report free space for privileged user
    static std::pair<uint64_t, uint64_t> getSpace(
        const std::string &path, bool privileged=false);
};



template<class X>
bool fs::readFirst(const std::string &file, X &x) {
    x = X();
    std::ifstream ifs(file.c_str());
    if (!ifs)
        return false;

    ifs >> x;

    if (!ifs) {
        x = X();
        return false;
    }

    return true;
}


} // end namespace util


#endif
