#ifndef CLI_HPP
#define CLI_HPP

#include <string>
#include <map>
#include <vector>

using args_t = std::multimap<std::string,std::string>;

namespace std {
template<typename T>
T begin(const std::pair<T,T>& p) {
    return p.first;
}
template<typename T>
T end(const std::pair<T,T>& p) {
    return p.second;
}
}

template<typename M>
M read_arguments(int argc, char** argv) {
    M map;

    for (int i = 1; i < argc; ++i) {
        std::string s(argv[i]);

        if (s[0] != '-') {
            map.insert(std::make_pair("", s));
            continue;
        }

        s.erase(0,1);

        std::size_t eqpos = s.find("=");
        if (eqpos != s.npos) {
            map.insert(std::make_pair(s.substr(0, eqpos), s.substr(eqpos+1)));
        } else {
            map.insert(std::make_pair(s, ""));
        }
    }

    return map;
}

template<typename T, typename M>
bool set_argument(T& arg, const std::string& name, M& args) {
    auto iter = args.find(name);
    if (iter != args.end()) {
        std::istringstream ss(iter->second);
        auto r = args.equal_range(name);
        args.erase(r.first, r.second);
        return ss >> arg;
    }

    return false;
}

template<typename M>
bool set_argument(bool& arg, const std::string& name, M& args) {
    auto iter = args.find(name);
    if (iter != args.end()) {
        if (iter->second.empty()) {
            arg = true;
        } else {
            arg = iter->second == "1" || iter->second == "true";
        }

        auto r = args.equal_range(name);
        args.erase(r.first, r.second);

        return true;
    }

    return false;
}

template<typename M>
auto get_arguments(M& args) -> decltype(args.equal_range(std::string())) {
    return args.equal_range("");
}

template<typename O, typename M>
void check_arguments(O& out, M& args) {
    for (auto& p : args) {
        if (!p.first.empty()) {
            out << "warning: unknown parameter '" << p.first << "'\n";
        }
    }

    out.flush();
}

#endif
