/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include "ecflow/base/cts/user/CtsApi.hpp"

#include <cassert>
#include <sstream>

#include "ecflow/core/Converter.hpp"

std::string CtsApi::to_string(const std::vector<std::string>& vec) {
    std::string ret;
    size_t vec_size = vec.size();
    for (size_t i = 0; i < vec_size; i++) {
        if (vec[i].empty())
            continue;
        ret += vec[i];
        if (i != vec_size - 1)
            ret += " "; // don't add space at the end
    }
    return ret;
}

std::string CtsApi::server_version() {
    return std::string("--server_version");
}
const char* CtsApi::server_version_arg() {
    return "server_version";
}

std::string CtsApi::get(const std::string& absNodePath) {
    std::string ret = "--get";
    if (!absNodePath.empty()) {
        ret += "=";
        ret += absNodePath;
    }
    return ret;
}
const char* CtsApi::getArg() {
    return "get";
}

std::string CtsApi::get_state(const std::string& absNodePath) {
    std::string ret = "--get_state";
    if (!absNodePath.empty()) {
        ret += "=";
        ret += absNodePath;
    }
    return ret;
}
const char* CtsApi::get_state_arg() {
    return "get_state";
}

std::string CtsApi::migrate(const std::string& absNodePath) {
    std::string ret = "--migrate";
    if (!absNodePath.empty()) {
        ret += "=";
        ret += absNodePath;
    }
    return ret;
}
const char* CtsApi::migrate_arg() {
    return "migrate";
}

std::string CtsApi::stats() {
    return "--stats";
}
const char* CtsApi::statsArg() {
    return "stats";
}
std::string CtsApi::stats_server() {
    return "--stats_server";
}
const char* CtsApi::stats_server_arg() {
    return "stats_server";
}
std::string CtsApi::stats_reset() {
    return "--stats_reset";
}
const char* CtsApi::stats_reset_arg() {
    return "stats_reset";
}

std::string CtsApi::suites() {
    return "--suites";
}
const char* CtsApi::suitesArg() {
    return "suites";
}

std::vector<std::string>
CtsApi::ch_register(int client_handle, bool auto_add_new_suites, const std::vector<std::string>& suites) {
    std::vector<std::string> retVec;
    retVec.reserve(suites.size() + 1);
    std::string ret = "--ch_register=";
    if (client_handle != 0) {
        ret += ecf::convert_to<std::string>(client_handle);
        retVec.push_back(ret);
        if (auto_add_new_suites)
            retVec.emplace_back("true");
        else
            retVec.emplace_back("false");
    }
    else {
        if (auto_add_new_suites)
            ret += "true";
        else
            ret += "false";
        retVec.push_back(ret);
    }
    for (const auto& suite : suites) {
        retVec.push_back(suite);
    }
    return retVec;
}
const char* CtsApi::ch_register_arg() {
    return "ch_register";
}

std::string CtsApi::ch_suites() {
    return "--ch_suites";
}
const char* CtsApi::ch_suites_arg() {
    return "ch_suites";
}

std::string CtsApi::ch_drop(int client_handle) {
    std::string ret = "--ch_drop=";
    ret += ecf::convert_to<std::string>(client_handle);
    return ret;
}
const char* CtsApi::ch_drop_arg() {
    return "ch_drop";
}

std::string CtsApi::ch_drop_user(const std::string& user) {
    std::string ret = "--ch_drop_user";
    if (!user.empty()) {
        ret += "=";
        ret += user;
    }
    return ret;
}
const char* CtsApi::ch_drop_user_arg() {
    return "ch_drop_user";
}

std::vector<std::string> CtsApi::ch_add(int client_handle, const std::vector<std::string>& suites) {
    std::vector<std::string> retVec;
    retVec.reserve(suites.size() + 1);
    std::string ret = "--ch_add=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    for (const auto& suite : suites) {
        retVec.push_back(suite);
    }
    return retVec;
}
const char* CtsApi::ch_add_arg() {
    return "ch_add";
}

std::vector<std::string> CtsApi::ch_remove(int client_handle, const std::vector<std::string>& suites) {
    std::vector<std::string> retVec;
    retVec.reserve(suites.size() + 1);
    std::string ret = "--ch_rem=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    for (const auto& suite : suites) {
        retVec.push_back(suite);
    }
    return retVec;
}
const char* CtsApi::ch_remove_arg() {
    return "ch_rem";
}

std::vector<std::string> CtsApi::ch_auto_add(int client_handle, bool auto_add_new_suites) {
    std::vector<std::string> retVec;
    retVec.reserve(2);
    std::string ret = "--ch_auto_add=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    if (auto_add_new_suites)
        retVec.emplace_back("true");
    else
        retVec.emplace_back("false");
    return retVec;
}
const char* CtsApi::ch_auto_add_arg() {
    return "ch_auto_add";
}

std::vector<std::string>
CtsApi::sync(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no) {
    std::vector<std::string> retVec;
    retVec.reserve(3);
    std::string ret = "--sync=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    retVec.push_back(ecf::convert_to<std::string>(state_change_no));
    retVec.push_back(ecf::convert_to<std::string>(modify_change_no));
    return retVec;
}
const char* CtsApi::syncArg() {
    return "sync";
}

std::vector<std::string>
CtsApi::sync_clock(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no) {
    std::vector<std::string> retVec;
    retVec.reserve(3);
    std::string ret = "--sync_clock=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    retVec.push_back(ecf::convert_to<std::string>(state_change_no));
    retVec.push_back(ecf::convert_to<std::string>(modify_change_no));
    return retVec;
}
const char* CtsApi::sync_clock_arg() {
    return "sync_clock";
}

std::string CtsApi::sync_full(unsigned int client_handle) {
    std::string ret = "--sync_full=";
    ret += ecf::convert_to<std::string>(client_handle);
    return ret;
}
const char* CtsApi::sync_full_arg() {
    return "sync_full";
}

std::vector<std::string>
CtsApi::news(unsigned int client_handle, unsigned int state_change_no, unsigned int modify_change_no) {
    std::vector<std::string> retVec;
    retVec.reserve(3);
    std::string ret = "--news=";
    ret += ecf::convert_to<std::string>(client_handle);
    retVec.push_back(ret);
    retVec.push_back(ecf::convert_to<std::string>(state_change_no));
    retVec.push_back(ecf::convert_to<std::string>(modify_change_no));
    return retVec;
}
const char* CtsApi::newsArg() {
    return "news";
}

std::vector<std::string> CtsApi::loadDefs(const std::string& filePath, bool force, bool check_only, bool print) {

    std::string ret = "--load=";
    ret += filePath;

    std::vector<std::string> retVec;
    retVec.reserve(3);
    retVec.push_back(ret);
    if (force)
        retVec.emplace_back("force");
    if (check_only)
        retVec.emplace_back("check_only");
    if (print)
        retVec.emplace_back("print");
    return retVec;
}
const char* CtsApi::loadDefsArg() {
    return "load";
}

std::string CtsApi::restartServer() {
    return "--restart";
}
const char* CtsApi::restartServerArg() {
    return "restart";
}

std::string CtsApi::haltServer(bool auto_confirm) {
    return (auto_confirm) ? "--halt=yes" : "--halt";
}
const char* CtsApi::haltServerArg() {
    return "halt";
}

std::string CtsApi::shutdownServer(bool auto_confirm) {
    return (auto_confirm) ? "--shutdown=yes" : "--shutdown";
}
const char* CtsApi::shutdownServerArg() {
    return "shutdown";
}

std::string CtsApi::terminateServer(bool auto_confirm) {
    return (auto_confirm) ? "--terminate=yes" : "--terminate";
}
const char* CtsApi::terminateServerArg() {
    return "terminate";
}

std::string CtsApi::pingServer() {
    return "--ping";
}
const char* CtsApi::pingServerArg() {
    return "ping";
}

std::string CtsApi::server_load(const std::string& path_to_log_file) {
    std::string ret = "--server_load";
    if (!path_to_log_file.empty()) {
        ret += "=";
        ret += path_to_log_file;
    }
    return ret;
}
const char* CtsApi::server_load_arg() {
    return "server_load";
}

std::string CtsApi::debug_server_on() {
    return "--debug_server_on";
}
const char* CtsApi::debug_server_on_arg() {
    return "debug_server_on";
}
std::string CtsApi::debug_server_off() {
    return "--debug_server_off";
}
const char* CtsApi::debug_server_off_arg() {
    return "debug_server_off";
}

std::string CtsApi::begin(const std::string& suiteName, bool force) {

    // *both* are optional
    std::string ret = "--begin";
    if (suiteName.empty() && !force) {
        return ret;
    }
    if (!suiteName.empty()) {
        ret += "=";
        ret += suiteName;
    }
    if (force) {
        if (suiteName.empty()) {
            ret += "=--force";
        }
        else {
            ret += " --force"; // note the space separator
        }
    }
    return ret;
}
const char* CtsApi::beginArg() {
    return "begin";
}

std::string CtsApi::checkJobGenOnly(const std::string& absNodePath) {
    std::string ret = "--checkJobGenOnly";
    if (!absNodePath.empty()) {
        ret += "=";
        ret += absNodePath;
    }
    return ret;
}
const char* CtsApi::checkJobGenOnlyArg() {
    return "checkJobGenOnly";
}

std::string CtsApi::job_gen(const std::string& absNodePath) {
    std::string ret = "--job_gen";
    if (!absNodePath.empty()) {
        ret += "=";
        ret += absNodePath;
    }
    return ret;
}
const char* CtsApi::job_genArg() {
    return "job_gen";
}

std::vector<std::string> CtsApi::check(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(2 + paths.size());
    retVec.emplace_back("--check");
    if (paths.empty())
        retVec.emplace_back("_all_");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::check(const std::string& path) {
    if (path.empty()) {
        return CtsApi::check(std::vector<std::string>());
    }
    return CtsApi::check(std::vector<std::string>(1, path));
}
const char* CtsApi::check_arg() {
    return "check";
}

std::vector<std::string> CtsApi::delete_node(const std::vector<std::string>& paths, bool force, bool auto_confirm) {
    std::vector<std::string> retVec;
    retVec.reserve(4 + paths.size());
    retVec.emplace_back("--delete");
    if (paths.empty()) {
        retVec.emplace_back("_all_");
    }
    if (force) {
        retVec.emplace_back("force");
    }
    if (auto_confirm) {             // By default delete prompts
        retVec.emplace_back("yes"); // yes means we don't prompt, and have automatically confirmed the delete
    }
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::delete_node(const std::string& absNodePath, bool force, bool auto_confirm) {
    if (absNodePath.empty())
        return CtsApi::delete_node(std::vector<std::string>(), force, auto_confirm);
    return CtsApi::delete_node(std::vector<std::string>(1, absNodePath), force, auto_confirm);
}
const char* CtsApi::delete_node_arg() {
    return "delete";
}

std::vector<std::string> CtsApi::suspend(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--suspend");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::suspend(const std::string& path) {
    return CtsApi::suspend(std::vector<std::string>(1, path));
}
const char* CtsApi::suspend_arg() {
    return "suspend";
}

std::vector<std::string> CtsApi::resume(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--resume");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::resume(const std::string& path) {
    return CtsApi::resume(std::vector<std::string>(1, path));
}
const char* CtsApi::resume_arg() {
    return "resume";
}

std::vector<std::string> CtsApi::kill(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--kill");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::kill(const std::string& path) {
    return CtsApi::kill(std::vector<std::string>(1, path));
}
const char* CtsApi::kill_arg() {
    return "kill";
}

std::vector<std::string> CtsApi::status(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--status");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::status(const std::string& path) {
    return CtsApi::status(std::vector<std::string>(1, path));
}
const char* CtsApi::statusArg() {
    return "status";
}

std::vector<std::string> CtsApi::edit_history(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--edit_history");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::edit_history(const std::string& path) {
    return CtsApi::edit_history(std::vector<std::string>(1, path));
}
const char* CtsApi::edit_history_arg() {
    return "edit_history";
}

std::vector<std::string> CtsApi::archive(const std::vector<std::string>& paths, bool force) {
    std::vector<std::string> retVec;
    retVec.reserve(2 + paths.size());
    retVec.emplace_back("--archive");
    if (force)
        retVec.emplace_back("force");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::archive(const std::string& path, bool force) {
    return CtsApi::archive(std::vector<std::string>(1, path), force);
}
const char* CtsApi::archive_arg() {
    return "archive";
}

std::vector<std::string> CtsApi::restore(const std::vector<std::string>& paths) {
    std::vector<std::string> retVec;
    retVec.reserve(1 + paths.size());
    retVec.emplace_back("--restore");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::restore(const std::string& path) {
    return CtsApi::restore(std::vector<std::string>(1, path));
}
const char* CtsApi::restore_arg() {
    return "restore";
}

std::string CtsApi::why(const std::string& absNodePath) {
    if (absNodePath.empty())
        return "--why";
    std::string ret = "--why=";
    ret += absNodePath;
    return ret;
}
const char* CtsApi::whyArg() {
    return "why";
}

std::string CtsApi::zombieGet() {
    return "--zombie_get";
}
const char* CtsApi::zombieGetArg() {
    return "zombie_get";
}

std::vector<std::string>
CtsApi::zombieFob(const std::vector<std::string>& paths, const std::string& process_id, const std::string& password) {
    std::string ret = "--zombie_fob=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    if (!password.empty())
        retVec.push_back(password); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieFobCli(const std::string& path) {
    std::string ret = "--zombie_fob=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieFobCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_fob";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieFobArg() {
    return "zombie_fob";
}

std::vector<std::string>
CtsApi::zombieFail(const std::vector<std::string>& paths, const std::string& process_id, const std::string& password) {
    std::string ret = "--zombie_fail=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieFailCli(const std::string& path) {
    std::string ret = "--zombie_fail=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieFailCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_fail";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieFailArg() {
    return "zombie_fail";
}

std::vector<std::string>
CtsApi::zombieAdopt(const std::vector<std::string>& paths, const std::string& process_id, const std::string& password) {
    std::string ret = "--zombie_adopt=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    if (!password.empty())
        retVec.push_back(password); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieAdoptCli(const std::string& path) {
    std::string ret = "--zombie_adopt=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieAdoptCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_adopt";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieAdoptArg() {
    return "zombie_adopt";
}

std::vector<std::string> CtsApi::zombieRemove(const std::vector<std::string>& paths,
                                              const std::string& process_id,
                                              const std::string& password) {
    std::string ret = "--zombie_remove=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    if (!password.empty())
        retVec.push_back(password); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieRemoveCli(const std::string& path) {
    std::string ret = "--zombie_remove=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieRemoveCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_remove";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieRemoveArg() {
    return "zombie_remove";
}

std::vector<std::string>
CtsApi::zombieBlock(const std::vector<std::string>& paths, const std::string& process_id, const std::string& password) {
    std::string ret = "--zombie_block=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    if (!password.empty())
        retVec.push_back(password); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieBlockCli(const std::string& path) {
    std::string ret = "--zombie_block=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieBlockCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_block";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieBlockArg() {
    return "zombie_block";
}

std::vector<std::string>
CtsApi::zombieKill(const std::vector<std::string>& paths, const std::string& process_id, const std::string& password) {
    std::string ret = "--zombie_kill=";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);
    if (!paths.empty())
        ret += paths[0];
    retVec.push_back(ret);
    for (size_t i = 1; i < paths.size(); i++)
        retVec.push_back(paths[i]);
    if (!process_id.empty())
        retVec.push_back(process_id); // Note: order is important, even if empty
    if (!password.empty())
        retVec.push_back(password); // Note: order is important, even if empty
    return retVec;
}
std::string CtsApi::zombieKillCli(const std::string& path) {
    std::string ret = "--zombie_kill=";
    ret += path;
    return ret;
}
std::vector<std::string> CtsApi::zombieKillCli(const std::vector<std::string>& paths) {
    std::string ret = "--zombie_kill";
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 1);
    retVec.push_back(ret);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::zombieKillArg() {
    return "zombie_kill";
}

std::vector<std::string> CtsApi::requeue(const std::vector<std::string>& paths, const std::string& option) {
    std::vector<std::string> retVec;
    retVec.reserve(2 + paths.size());
    retVec.emplace_back("--requeue");
    if (!option.empty())
        retVec.push_back(option);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::requeue(const std::string& absNodePath, const std::string& option) {
    return CtsApi::requeue(std::vector<std::string>(1, absNodePath), option);
}
const char* CtsApi::requeueArg() {
    return "requeue";
}

std::vector<std::string> CtsApi::run(const std::vector<std::string>& paths, bool force) {
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 2);
    retVec.emplace_back("--run");
    if (force)
        retVec.emplace_back("force");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::run(const std::string& absNodePath, bool force) {
    return CtsApi::run(std::vector<std::string>(1, absNodePath), force);
}
const char* CtsApi::runArg() {
    return "run";
}

std::vector<std::string> CtsApi::order(const std::string& absNodePath, const std::string& orderType) {
    std::vector<std::string> retVec;
    retVec.reserve(2);
    std::string ret = "--order=";
    ret += absNodePath;
    retVec.push_back(ret);
    retVec.push_back(orderType);
    return retVec;
}
const char* CtsApi::orderArg() {
    return "order";
}

std::vector<std::string> CtsApi::replace(const std::string& absNodePath,
                                         const std::string& path_to_client_defs,
                                         bool create_parents_as_required,
                                         bool force) {
    std::vector<std::string> retVec;
    retVec.reserve(3);

    std::string ret = "--replace=";
    ret += absNodePath;
    retVec.push_back(ret);
    retVec.push_back(path_to_client_defs);
    if (create_parents_as_required)
        retVec.emplace_back("parent");
    if (force)
        retVec.emplace_back("force");

    return retVec;
}
const char* CtsApi::replace_arg() {
    return "replace";
}

std::string CtsApi::checkPtDefs(ecf::CheckPt::Mode m, int check_pt_interval, int check_pt_save_time_alarm) {
    std::string ret = "--check_pt";
    if (m != ecf::CheckPt::UNDEFINED || check_pt_interval != 0 || check_pt_save_time_alarm != 0)
        ret += "=";

    switch (m) {
        case ecf::CheckPt::NEVER:
            ret += "never";
            break;
        case ecf::CheckPt::ON_TIME:
            ret += "on_time";
            break;
        case ecf::CheckPt::ALWAYS:
            ret += "always";
            break;
        case ecf::CheckPt::UNDEFINED:
            break; // leave empty
        default:
            assert(false);
            break;
    }

    if (check_pt_interval != 0) {
        if (m != ecf::CheckPt::UNDEFINED)
            ret += ":";
        ret += ecf::convert_to<std::string>(check_pt_interval);
    }
    else {
        if (m == ecf::CheckPt::UNDEFINED && check_pt_save_time_alarm != 0) {
            ret += "alarm:";
            ret += ecf::convert_to<std::string>(check_pt_save_time_alarm);
        }
    }
    return ret;
}
const char* CtsApi::checkPtDefsArg() {
    return "check_pt";
}

std::string CtsApi::restoreDefsFromCheckPt() {
    return "--restore_from_checkpt";
}
const char* CtsApi::restoreDefsFromCheckPtArg() {
    return "restore_from_checkpt";
}

std::string CtsApi::logMsg(const std::string& theMsgToLog) {
    std::string ret = "--msg=";
    ret += theMsgToLog;
    return ret;
}
const char* CtsApi::logMsgArg() {
    return "msg";
}

std::vector<std::string> CtsApi::force(const std::vector<std::string>& paths,
                                       const std::string& state_or_event,
                                       bool recursive,
                                       bool set_repeats_to_last_value) {
    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 3);

    std::string ret = "--force=";
    ret += state_or_event;
    retVec.push_back(ret);
    if (recursive)
        retVec.emplace_back("recursive");
    if (set_repeats_to_last_value)
        retVec.emplace_back("full");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}

std::vector<std::string> CtsApi::force(const std::string& path,
                                       const std::string& state_or_event,
                                       bool recursive,
                                       bool set_repeats_to_last_value) {
    return CtsApi::force(std::vector<std::string>(1, path), state_or_event, recursive, set_repeats_to_last_value);
}
const char* CtsApi::forceArg() {
    return "force";
}

std::vector<std::string>
CtsApi::freeDep(const std::vector<std::string>& paths, bool trigger, bool all, bool date, bool time) {

    std::vector<std::string> retVec;
    retVec.reserve(paths.size() + 4);

    retVec.emplace_back("--free-dep");
    if (all)
        retVec.emplace_back("all");
    else {
        if (trigger)
            retVec.emplace_back("trigger");
        if (date)
            retVec.emplace_back("date");
        if (time)
            retVec.emplace_back("time");
    }
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::freeDep(const std::string& path, bool trigger, bool all, bool date, bool time) {

    return CtsApi::freeDep(std::vector<std::string>(1, path), trigger, all, date, time);
}
const char* CtsApi::freeDepArg() {
    return "free-dep";
}

std::vector<std::string>
CtsApi::file(const std::string& absNodePath, const std::string& fileType, const std::string& max_lines) {
    std::vector<std::string> retVec;
    retVec.reserve(3);
    std::string ret = "--file=";
    ret += absNodePath;
    retVec.push_back(ret);
    retVec.push_back(fileType);
    retVec.push_back(max_lines);
    return retVec;
}
const char* CtsApi::fileArg() {
    return "file";
}

std::vector<std::string> CtsApi::plug(const std::string& sourcePath, const std::string& destPath) {
    std::vector<std::string> retVec;
    retVec.reserve(2);

    std::string ret = "--plug=";
    ret += sourcePath;
    retVec.push_back(ret);
    retVec.push_back(destPath);

    return retVec;
}
const char* CtsApi::plugArg() {
    return "plug";
}

std::vector<std::string> CtsApi::alter(const std::vector<std::string>& paths,
                                       const std::string& alterType,
                                       const std::string& attrType,
                                       const std::string& name,
                                       const std::string& value) {
    std::vector<std::string> retVec;
    retVec.reserve(5 + paths.size());

    retVec.emplace_back("--alter");
    retVec.push_back(alterType);
    retVec.push_back(attrType);
    if (!name.empty())
        retVec.push_back(name);
    if (!value.empty())
        retVec.push_back(value);
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
std::vector<std::string> CtsApi::alter(const std::string& path,
                                       const std::string& alterType,
                                       const std::string& attrType,
                                       const std::string& name,
                                       const std::string& value) {
    return CtsApi::alter(std::vector<std::string>(1, path), alterType, attrType, name, value);
}

std::vector<std::string>
CtsApi::alter_sort(const std::vector<std::string>& paths, const std::string& sortable_attribute_name, bool recursive) {
    std::vector<std::string> retVec;
    retVec.reserve(2 + paths.size());

    retVec.emplace_back("--alter");
    retVec.emplace_back("sort");
    retVec.push_back(sortable_attribute_name);
    if (recursive)
        retVec.emplace_back("recursive");
    std::copy(paths.begin(), paths.end(), std::back_inserter(retVec));
    return retVec;
}
const char* CtsApi::alterArg() {
    return "alter";
}

std::string CtsApi::reloadwsfile() {
    return "--reloadwsfile";
}
const char* CtsApi::reloadwsfileArg() {
    return "reloadwsfile";
}

std::string CtsApi::reloadpasswdfile() {
    return "--reloadpasswdfile";
}
const char* CtsApi::reloadpasswdfile_arg() {
    return "reloadpasswdfile";
}

std::string CtsApi::reloadcustompasswdfile() {
    return "--reloadcustompasswdfile";
}
const char* CtsApi::reloadcustompasswdfile_arg() {
    return "reloadcustompasswdfile";
}

std::string CtsApi::group(const std::string& cmds) {
    std::string ret = "--group=";
    ret += cmds;
    return ret;
}
const char* CtsApi::groupArg() {
    return "group";
}

std::vector<std::string> CtsApi::getLog(int lastLine) {
    std::vector<std::string> retVec;
    retVec.reserve(2);
    retVec.emplace_back("--log=get");
    if (lastLine != 0) {
        std::stringstream ss;
        ss << lastLine;
        retVec.push_back(ss.str());
    }
    return retVec;
}
std::vector<std::string> CtsApi::new_log(const std::string& new_path) {
    std::vector<std::string> retVec;
    retVec.reserve(2);
    retVec.emplace_back("--log=new");
    if (!new_path.empty())
        retVec.push_back(new_path);
    return retVec;
}
std::string CtsApi::clearLog() {
    return "--log=clear";
}
std::string CtsApi::flushLog() {
    return "--log=flush";
}
std::string CtsApi::get_log_path() {
    return "--log=path";
}

std::string CtsApi::forceDependencyEval() {
    return "--force-dep-eval";
}
const char* CtsApi::forceDependencyEvalArg() {
    return "force-dep-eval";
}

std::vector<std::string> CtsApi::edit_script(const std::string& path_to_task,
                                             const std::string& edit_type,
                                             const std::string& path_to_script,
                                             bool create_alias,
                                             bool run) {
    std::vector<std::string> retVec;
    std::string ret = "--edit_script=";
    ret += path_to_task;
    retVec.push_back(ret);
    retVec.push_back(edit_type);
    if (!path_to_script.empty())
        retVec.push_back(path_to_script);
    if (create_alias)
        retVec.emplace_back("create_alias");
    if (!run)
        retVec.emplace_back("no_run");
    return retVec;
}
const char* CtsApi::edit_script_arg() {
    return "edit_script";
}

std::vector<std::string>
CtsApi::query(const std::string& query_type, const std::string& path_to_attribute, const std::string& attribute) {
    std::vector<std::string> retVec;
    retVec.reserve(3);
    std::string ret = "--query=";
    ret += query_type;
    retVec.push_back(ret);
    if (query_type == "event" || query_type == "meter" || query_type == "variable") {
        retVec.push_back(path_to_attribute + ":" + attribute);
    }
    else if (query_type == "trigger") {
        retVec.push_back(path_to_attribute);
        retVec.push_back(attribute);
    }
    else if (query_type == "repeat") {
        retVec.push_back(path_to_attribute);
        if (!attribute.empty())
            retVec.push_back(attribute);
    }
    else if (query_type == "state" || query_type == "dstate") {
        retVec.push_back(path_to_attribute);
    }
    return retVec;
}
const char* CtsApi::queryArg() {
    return "query";
}
