#include "pack.h"
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <iostream>

namespace fs = boost::filesystem;

bool CPackBinary::startPack(const CmdResult& result)
{
    result_ = result;
    auto dpends = getDepends(result_.binary, result.lib_dirs);
    auto should_copy = parseResult(dpends);
    return handleAndCopy(should_copy, result_.purpose_dir);
}

std::vector<std::string>
CPackBinary::getDepends(const std::string& path,
                        const std::vector<std::string>& dirs)
{
    std::vector<std::string> result;
    std::string cmds;
    cmds.append("export LD_LIBRARY_PATH=$LD_LIBRARY_PATH");
    for (const auto& item : dirs) {
        cmds.append(":" + item);
    }
    cmds.append(" && ldd " + path);

    auto* pf = popen(cmds.c_str(), "r");
    if (pf == nullptr) {
        return result;
    }
    char buffer[1024]{};
    std::string output{};
    while (std::fgets(buffer, sizeof(buffer), pf)) {
        output.append(buffer);
    }
    fclose(pf);

    std::vector<std::string> split;
    boost::split(split, output, boost::is_any_of("\t"));
    for (const auto& item : split) {
        result.push_back(item);
    }
    return result;
}

std::list<std::string>
CPackBinary::parseResult(const std::vector<std::string>& result)
{
    std::list<std::string> ret;
    auto backup = result;

    for (auto& item : backup) {
        if (item.empty()) {
            continue;
        }
        if (boost::contains(item, "not found")) {
            std::cout << "未找到依赖:" << item << std::endl;
            continue;
        }
        boost::replace_all(item, "=>", "");
        std::vector<std::string> split;
        boost::split(split, item, boost::is_any_of(" "));
        std::string h;
        if (split.size() == 4) {
            h = split[2];
        }
        if (split.size() == 3) {
            h = split[1];
        }
        if (boost::starts_with(h, "/lib")) {
            continue;
        }
        if (!h.empty()) {
            ret.push_back(h);
            std::cout << "依赖:" << h << std::endl;
        }
    }
    ret.push_back(result_.binary);
    return ret;
}

bool CPackBinary::handleAndCopy(const std::list<std::string>& libs,
                                const std::string& des)
{
    auto filename = fs::path(result_.binary).filename().string();
    auto dest_directory = fs::path(des).append(filename);

    try {
        fs::create_directories(dest_directory);
        for (const auto& item : libs) {
            auto item_name = fs::path(item).filename().string();
            auto newpath = fs::path(dest_directory).append(item_name);
            fs::copy_file(item, newpath, fs::copy_options::overwrite_existing);
        }
        return true;
    } catch (const std::exception& e) {
        std::cerr << e.what() << '\n';
        return false;
    }
}