#ifndef CNOID_STDX_FILESYSTEM_HEADER
#define CNOID_STDX_FILESYSTEM_HEADER

#if __cplusplus > 201402L

#include <chrono>

#if ((defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 8)) || \
     (defined(__clang__) && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE < 8)))

#include <experimental/filesystem>
namespace std::experimental::filesystem {

inline path lexically_normal(const path& p){
    // lexically_normal or any other normalization functions are not
    // implemented in the experimental filesystem implementation
    return p;
}

inline path absolute(const path& p, std::error_code& ec)
{
    return absolute(p);
}

#else

#include <filesystem>
namespace std::filesystem {

inline path lexically_normal(const path& p){
    return p.lexically_normal();
}

#endif

inline std::time_t last_write_time_to_time_t(const path& p){
    return std::chrono::duration_cast<std::chrono::system_clock::duration>(
        last_write_time(p).time_since_epoch()).count();
}

} // namespace

namespace cnoid::stdx {

#if ((defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 8)) || \
     (defined(__clang__) && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE < 8)))

namespace filesystem = std::experimental::filesystem;

#else

namespace filesystem = std::filesystem;

#endif

typedef std::error_code error_code;
typedef filesystem::copy_options copy_options;
}

#else // __cplusplus > 201402L

#include <boost/filesystem.hpp>
namespace boost { namespace filesystem {

inline std::time_t last_write_time_to_time_t(const path& p){
    return last_write_time(p);
}

#if BOOST_VERSION < 107400
inline path absolute(const path& p, system::error_code& ec)
{
    return absolute(p);
}
#endif

inline path lexically_normal(const path& p){
#if BOOST_VERSION < 106000
    path n(p);
    return n.normalize();
#else
    return p.lexically_normal();
#endif
}

inline bool copy_directory_recursively(const path& src, const path& dest, system::error_code& ec)
{
    namespace fs = boost::filesystem;

    if(!fs::exists(src, ec) || !fs::is_directory(src, ec)){
        return false;
    }
    if(!fs::exists(dest, ec)){
        if(!fs::create_directory(dest)){
            return false;
        }
    }
    for(fs::directory_iterator it(src); it != fs::directory_iterator(); ++it){
        fs::path current(it->path());
        if(fs::is_directory(current)){
            if(!copy_directory_recursively(current, dest / current.filename(), ec)){
                return false;
            }
        } else {
            fs::copy_file(current, dest / current.filename(), ec);
            if(ec){
                return false;
            }
        }
    }
    return true;
}

} }

namespace cnoid { namespace stdx {
namespace filesystem = boost::filesystem;
typedef boost::system::error_code error_code;
typedef boost::filesystem::copy_option copy_options;
} }
#endif

#endif
