#include "multi_thread_down.h"

void CTimer::start()
{
    m_start = std::chrono::high_resolution_clock::now();
}

size_t CTimer::getTime()
{
    m_end = std::chrono::high_resolution_clock::now();
    std::chrono::milliseconds duration = std::chrono::duration_cast<std::chrono::milliseconds>(m_end - m_start);
    size_t cnt = duration.count();
    return cnt;
}

CThreadDownload::CThreadDownload()
= default;

CThreadDownload::~CThreadDownload()
= default;

double CThreadDownload::getFileLength(const char* url)
{
    double len = 0;
    CURL* curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
    if (curl_easy_perform(curl) == CURLE_OK) {
        curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &len);
    }
    else {
        len = -1;
    }
    curl_easy_cleanup(curl);
    return len;
}

int CThreadDownload::download(const char* url, const char* filename) {

    double fileLen = getFileLength(url);
    if (fileLen < 0) {
        std::printf("Failed to obtain the file size!");
        return -1;
    }

    std::ofstream stream(filename, std::ios::binary | std::ios::trunc);
    if (!stream.is_open()) {
        std::printf("Open File Failed: %s", filename);
        return -1;
    }
    m_fstream = std::move(stream);


    std::printf("File Len: %lf\n", fileLen);

    // try
    // {
    //     m_fstream.seekp(fileLen - 1);
    // }
    // catch(const std::exception& e)
    // {
    //     std::cerr << e.what() << '\n';
    //     m_fstream.close();
    //     return -1;
    // }

    CURL* curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunCall);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);

    // 建立TCP连接,发送http请求,等待数据返回
    CURLcode res = curl_easy_perform(curl);

    if (res != CURLE_OK) {
        std::printf("res: %d\n", res);
    }

    curl_easy_cleanup(curl);
    m_fstream.close();
    std::cout << "Done." << std::endl;
    return 0;
}

size_t CThreadDownload::writeFunCall(void* ptr, size_t size, size_t mmb, void* userdata)
{
    size_t nSize = size * mmb;
    CThreadDownload* pDown = (CThreadDownload*)userdata;
    pDown->m_fstream.write((const char*)ptr, nSize);
    std::printf("writeFunCall: %ld\n", nSize);
    return nSize;
}