/*
 * 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 <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/test/unit_test.hpp>

using namespace std;
namespace po = boost::program_options;

BOOST_AUTO_TEST_SUITE(U_Base)

BOOST_AUTO_TEST_SUITE(T_ProgramOptions)

BOOST_AUTO_TEST_CASE(test_program_options_implicit_value) {
    cout << "Base:: ...test_program_options_implicit_value\n";

    // Declare the supported options.
    po::options_description desc("Allowed options");
    desc.add_options()("help", "produce help message")(
        "arg1", po::value<string>()->implicit_value(string("")), "optional arg1 description");

    {
        char* argv[] = {const_cast<char*>("test_program_options_implicit_value"),
                        const_cast<char*>("--help"),
                        const_cast<char*>("--arg1")};

        po::variables_map vm;
        po::store(po::parse_command_line(3, argv, desc), vm); // populate variable map
        po::notify(vm);                                       // raise any errors

        BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
        BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
        BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "", "Expected arg1 to be empty");
    }
    //   {
    //      // This test fails on boost 1.59, can't cope --arg1 10, only --arg1=10 *******
    //      // See: ECFLOW-509 and https://svn.boost.org/trac/boost/ticket/11893
    //      char* argv[] = {
    //            const_cast<char*>("test_program_options_implicit_value"),
    //            const_cast<char*>("--arg1"),
    //            const_cast<char*>("10")
    //      };
    //
    //      po::variables_map vm;
    ////      po::store(po::parse_command_line(3, argv, desc,
    ////                        po::command_line_style::unix_style ^ po::command_line_style::allow_short ^
    ////                        po::command_line_style::long_allow_adjacent |
    ////                        po::command_line_style::short_allow_adjacent |
    ////                        po::command_line_style::allow_long_disguise
    ////                ), vm);
    //
    //      po::store(po::command_line_parser(3,argv).options(desc).style(
    //                       po::command_line_style::long_allow_next |
    //                       po::command_line_style::allow_long_disguise |
    //                       po::command_line_style::long_allow_adjacent).run(),
    //                vm);
    //      po::notify(vm);
    //
    //      BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
    //      BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "10", "Expected arg1 with value of 10 but found '" <<
    //      vm["arg1"].as<string>() << "'");
    //   }

    {
        char* argv[] = {const_cast<char*>("test_program_options_implicit_value"), const_cast<char*>("--arg1=11")};

        po::variables_map vm;
        po::store(po::parse_command_line(2, argv, desc), vm);
        po::notify(vm);

        BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");
        BOOST_CHECK_MESSAGE(vm["arg1"].as<string>() == "11",
                            "Expected arg1 with value of 11 but found " << vm["arg1"].as<string>());
    }
}

BOOST_AUTO_TEST_CASE(test_program_options_multitoken) {
    cout << "Base:: ...test_program_options_multitoken\n";

    // Declare the supported options.
    po::options_description desc("Allowed options");
    desc.add_options()("help",
                       "produce help message")("arg1", po::value<vector<string>>()->multitoken(), "arg1 description");

    char* argv[] = {const_cast<char*>("test_program_options_multitoken"),
                    const_cast<char*>("--help"),
                    const_cast<char*>("--arg1"),
                    const_cast<char*>("a"),
                    const_cast<char*>("b")};

    po::variables_map vm;
    po::store(po::parse_command_line(5, argv, desc), vm);
    po::notify(vm);

    BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
    BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");

    std::vector<string> expected;
    expected.emplace_back("a");
    expected.emplace_back("b");
    BOOST_CHECK_MESSAGE(vm["arg1"].as<vector<string>>() == expected, "multi-token not as expected");
}

BOOST_AUTO_TEST_CASE(test_program_options_multitoken_with_negative_values) {
    cout << "Base:: ...test_program_options_multitoken_with_negative_values\n";

    // Declare the supported options.
    po::options_description desc("Allowed options");
    desc.add_options()("help",
                       "produce help message")("arg1", po::value<vector<string>>()->multitoken(), "arg1 description");

    char* argv[] = {const_cast<char*>("test_program_options_multitoken_1"),
                    const_cast<char*>("--help"),
                    const_cast<char*>("--arg1"),
                    const_cast<char*>("-1"),
                    const_cast<char*>("-w")};

    //  --alter delete cron -w 0,1 10:00 /s1     # -w treated as option
    //  --alter=/s1 change meter name -1         # -1 treated as option
    // Note: negative numbers get treated as options: i.e trying to change meter value to a negative number
    //  To avoid negative numbers from being treated as option use, we need to change command line style:
    //       po::command_line_style::unix_style ^ po::command_line_style::allow_short

    po::variables_map vm;
    po::store(
        po::parse_command_line(5, argv, desc, po::command_line_style::unix_style ^ po::command_line_style::allow_short),
        vm);
    po::notify(vm);

    BOOST_CHECK_MESSAGE(vm.count("help"), "Expected help");
    BOOST_CHECK_MESSAGE(vm.count("arg1"), "Expected arg1");

    std::vector<string> expected;
    expected.emplace_back("-1");
    expected.emplace_back("-w");
    BOOST_CHECK_MESSAGE(vm["arg1"].as<vector<string>>() == expected, "multi-token not as expected");
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
