
#ifndef ILOGGER_HPP
#define ILOGGER_HPP


#include <string>
#include <vector>
#include <tuple>
#include <time.h>
#include <functional>

#if defined(_WIN32)
#	define U_OS_WINDOWS
#else
#   define U_OS_LINUX
#endif


namespace iLogger{

    using namespace std;

    enum class LogLevel : int{
        Debug   = 5,
        Verbose = 4,
        Info    = 3,
        Warning = 2,
        Error   = 1,
        Fatal   = 0
    };

    typedef function<void(const char* file, int line, LogLevel level, const string& message)> log_hook_func;

    #define INFOD(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Debug, __VA_ARGS__)
    #define INFOV(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Verbose, __VA_ARGS__)
    #define INFO(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Info, __VA_ARGS__)
    #define INFOW(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Warning, __VA_ARGS__)
    #define INFOE(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Error, __VA_ARGS__)
    #define INFOF(...)			iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Fatal, __VA_ARGS__)

    string date_now();
    string time_now();
    string gmtime_now();
	string gmtime(time_t t);
	time_t gmtime2ctime(const string& gmt);
    void sleep(int ms);

    bool isfile(const string& file);
    bool mkdir(const string& path);
    bool mkdirs(const string& path);
    bool delete_file(const string& path);
    bool rmtree(const string& directory, bool ignore_fail=false);
    bool exists(const string& path);
    string format(const char* fmt, ...);
    FILE* fopen_mkdirs(const string& path, const string& mode);
    string file_name(const string& path, bool include_suffix=true);
    string directory(const string& path);
    long long timestamp_now();
    double timestamp_now_float();
    time_t last_modify(const string& file);
    vector<uint8_t> load_file(const string& file);
    string load_text_file(const string& file);
    size_t file_size(const string& file);

    bool begin_with(const string& str, const string& with);
	bool end_with(const string& str, const string& with);
    vector<string> split_string(const string& str, const std::string& spstr);
    string replace_string(const string& str, const string& token, const string& value, int nreplace=-1, int* out_num_replace=nullptr);

    // h[0-1], s[0-1], v[0-1]
    // return, 0-255, 0-255, 0-255
    tuple<uint8_t, uint8_t, uint8_t> hsv2rgb(float h, float s, float v);
    tuple<uint8_t, uint8_t, uint8_t> random_color(int id);

    //   abcdefg.pnga          *.png      > false
	//   abcdefg.png           *.png      > true
	//   abcdefg.png          a?cdefg.png > true
	bool pattern_match(const char* str, const char* matcher, bool igrnoe_case = true);
    vector<string> find_files(
        const string& directory, 
        const string& filter = "*", bool findDirectory = false, bool includeSubDirectory = false);

    string align_blank(const string& input, int align_size, char blank=' ');
    bool save_file(const string& file, const vector<uint8_t>& data, bool mk_dirs = true);
    bool save_file(const string& file, const string& data, bool mk_dirs = true);
	bool save_file(const string& file, const void* data, size_t length, bool mk_dirs = true);

    // 捕获：SIGINT(2)、SIGQUIT(3)
    int while_loop();

    // 关于logger的api
    const char* level_string(LogLevel level);
    void set_logger_save_directory(const string& loggerDirectory);
    void set_logger_hook(const log_hook_func& func);
    void set_log_level(LogLevel level);
    LogLevel get_log_level();
    void __log_func(const char* file, int line, LogLevel level, const char* fmt, ...);
    void destroy_logger();

    string base64_decode(const string& base64);
    string base64_encode(const void* data, size_t size);

    inline int upbound(int n, int align = 32){return (n + align - 1) / align * align;}
    string join_dims(const vector<int64_t>& dims);
};


#endif // ILOGGER_HPP