#include <cstring>
#include "TimeUtil.h"

namespace ai_matrix
{
    const int TIME_DIFF = 28800; // 8 hour
    TimeUtil *TimeUtil::ins = nullptr;
    TimeUtil::GarbageCollector TimeUtil::gc;
    std::mutex TimeUtil::mx;

    TimeUtil *TimeUtil::getins()
    {
        //双层锁，确保线程安全
        if (ins == nullptr)
        {
            std::lock_guard<std::mutex> guard(mx); //防止异常发生不能解锁
            if (ins == nullptr)
            {
                ins = new TimeUtil();
            }
        }
        return ins;
    }

    /**
     * 获取用于文件命名的时间戳
     * @return
     */
    std::string TimeUtil::get_timestamp_file()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[30] = {0};
        sprintf(tmp, "%04d-%02d-%02d-%02d-%02d-%02d-%03d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, msec);

        return std::string(tmp);
    }

    /**
     * 获取用用于日志记录的时间
     * @return yyyy-MM-dd hh:mm:ss.us
     */
    std::string TimeUtil::getDateTime_usec()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[30] = {0};
        sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d.%03d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, msec);

        return std::string(tmp);
    }

    /**
     *  获取北京当前日期
     *  @return  : 日期 yyyy-mm-dd
     */
    std::string TimeUtil::getDate()
    {
        struct timeval time = {0, 0};
        gettimeofday(&time, nullptr);
        time_t timep = time.tv_sec + TIME_DIFF;

        struct tm *p = gmtime(&timep);

        char szTmp[12] = {0};
        sprintf(szTmp, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        return std::string(szTmp);
    }

    /**
     * 获取北京当前时间
     * @return  : 时间 hh:mm:ss
     */
    std::string TimeUtil::getTime()
    {
        struct timeval time = {0, 0};
        gettimeofday(&time, nullptr);
        time_t timep = time.tv_sec + TIME_DIFF;

        struct tm *p = gmtime(&timep);

        char szTmp[10] = {0};
        sprintf(szTmp, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec);
        return std::string(szTmp);
    }

    /**
     * 获取当前 日期+时间
     * @return yyyy-MM-dd hh:mm:ss
     */
    std::string TimeUtil::getDateTime()
    {
        struct timeval time = {0, 0};
        gettimeofday(&time, nullptr);
        time_t timep = time.tv_sec + TIME_DIFF;

        struct tm *p = gmtime(&timep);
        int msec = time.tv_usec / 1000;

        char szTmp[32] = {0};
        sprintf(szTmp, "%04d-%02d-%02d %02d:%02d:%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);

        return std::string(szTmp);
    }

    /**
     * 获取用于文件名的时间
     * @return hh-mm-ss
     */
	std::string TimeUtil::getTime_file()
	{
		time_t timep = time(NULL);
		struct tm *p = localtime(&timep);

		struct timeval tv;
		gettimeofday(&tv, NULL);

		int msec = tv.tv_usec / 1000;

		char tmp[10] = { 0 };
		sprintf(tmp, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

		return std::string(tmp);
	}

    /**
    *
    * inParam : N/A
    * outParam: N/A
    * return  : 时间戳
    */
    /**
     * 获取当前时间距1970年的秒数(可选毫秒数)
     * @param usec 是否取毫秒数
     * @return
     */
    uint64_t TimeUtil::getCurrentTimeMillis(bool usec)
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        if (usec)
            return tv.tv_sec * 1000 + tv.tv_usec / 1000;
        else
            return tv.tv_sec;
    }

    /**
    * 获取指定时间距1970年的秒数 (入参格式：YYYY-MM-DD hh-mm-ss)
    * inParam : std::string &strDateTime    日期时间
    * outParam: N/A
    * return  : 时间戳
    */
    uint64_t TimeUtil::getParamTimeMilliSeconds(std::string &strDateTime)
    {
//        LogDebug << "strDateTime:" << strDateTime;
        if (strDateTime.length() != 19)
        {
            return 0;
        }

        int iYear = atoi(strDateTime.substr(0, 4).c_str());
        int iMon = atoi(strDateTime.substr(5, 2).c_str());
        int iDay = atoi(strDateTime.substr(8, 2).c_str());
        int iHour = atoi(strDateTime.substr(11, 2).c_str());
        int iMin = atoi(strDateTime.substr(14, 2).c_str());
        int iSec = atoi(strDateTime.substr(17, 2).c_str());

        struct tm stm;
        memset(&stm, 0, sizeof(stm));
        stm.tm_year = iYear - 1900;
        stm.tm_mon = iMon - 1;
        stm.tm_mday = iDay;
        stm.tm_hour = iHour;
        stm.tm_min = iMin;
        stm.tm_sec = iSec;

        uint64_t i64Ret = (uint64_t)mktime(&stm) * 1000;
        return i64Ret;
    }

    /**
     * 获取指定毫秒数的对应的北京日期时间
     * inParam : uint64_t i64MilliSeconds
     * outParam: N/A
     * return  : 日期时间
     */
    std::string TimeUtil::getDateTimeByMilliSeconds(uint64_t i64MilliSeconds)
    {
        time_t timep = i64MilliSeconds / 1000 + TIME_DIFF;
        struct tm *p = gmtime(&timep);

        char szTmp[32] = {0};
        sprintf(szTmp, "%04d-%02d-%02d %02d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);

        return std::string(szTmp);
    }

    //时间戳转化为时间 毫秒级
    std::string TimeUtil::Stamp2Time(long long timestamp, bool has_msec)
    {
        int ms = timestamp % 1000;//取毫秒
        time_t tick = (time_t)(timestamp/1000);//转换时间
        struct tm tm;
        char s[40];
        tm = *localtime(&tick);
        strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
        std::string str(s);
        if (has_msec)
        {
            str = str+ "." + std::to_string(ms);
        }
        return str;
    }
}
