// generate boost::program_options object for the routing part
inline unsigned GenerateServerProgramOptions(const int argc,
                                             const char *argv[],
                                             ServerPaths &paths,
                                             std::string &ip_address,
                                             int &ip_port,
                                             int &requested_num_threads,
                                             bool &use_shared_memory,
                                             bool &trial,
                                             int &max_locations_distance_table,
                                             int &max_locations_map_matching)
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
        "config,c", boost::program_options::value<boost::filesystem::path>(&paths["config"])
                        ->default_value("server.ini"),
        "Path to a configuration file")(
        "trial", boost::program_options::value<bool>(&trial)->implicit_value(true),
        "Quit after initialization");

    // declare a group of options that will be allowed both on command line
    // as well as in a config file
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()(
        "hsgrdata", boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
        ".hsgr file")("nodesdata",
                      boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
                      ".nodes file")(
        "edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
        ".edges file")("geometry",
                       boost::program_options::value<boost::filesystem::path>(&paths["geometries"]),
                       ".geometry file")(
        "ramindex", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
        ".ramIndex file")(
        "fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
        "File index file")(
        "namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
        ".names file")("timestamp",
                       boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
                       ".timestamp file")(
        "ip,i", boost::program_options::value<std::string>(&ip_address)->default_value("0.0.0.0"),
        "IP address")("port,p", boost::program_options::value<int>(&ip_port)->default_value(5000),
                      "TCP/IP port")(
        "threads,t", boost::program_options::value<int>(&requested_num_threads)->default_value(8),
        "Number of threads to use")(
        "shared-memory,s",
        boost::program_options::value<bool>(&use_shared_memory)->implicit_value(true),
        "Load data from shared memory")(
        "max-table-size,m",
        boost::program_options::value<int>(&max_locations_distance_table)->default_value(1000000),
        "Max. locations supported in distance table query")(
        "max-matching-size,m",
        boost::program_options::value<int>(&max_locations_map_matching)->default_value(2),
        "Max. locations supported in map matching query");

    // hidden options, will be allowed both on command line and in config
    // file, but will not be shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()(
        "base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
        "base path to .osrm file");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("base", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    boost::program_options::options_description config_file_options;
    config_file_options.add(config_options).add(hidden_options);

    boost::program_options::options_description visible_options(
        boost::filesystem::basename(argv[0]) + " <base.osrm> [<options>]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    boost::program_options::variables_map option_variables;
    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                      .options(cmdline_options)
                                      .positional(positional_options)
                                      .run(),
                                  option_variables);

    if (option_variables.count("version"))
    {
        SimpleLogger().Write() << g_GIT_DESCRIPTION;
        return INIT_OK_DO_NOT_START_ENGINE;
    }

    if (option_variables.count("help"))
    {
        SimpleLogger().Write() << visible_options;
        return INIT_OK_DO_NOT_START_ENGINE;
    }

    boost::program_options::notify(option_variables);

    // parse config file
    auto path_iterator = paths.find("config");
    if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
        !option_variables.count("base"))
    {
        SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
        std::string ini_file_contents = read_file_lower_content(path_iterator->second);
        std::stringstream config_stream(ini_file_contents);
        boost::program_options::store(parse_config_file(config_stream, config_file_options),
                                      option_variables);
        boost::program_options::notify(option_variables);
        return INIT_OK_START_ENGINE;
    }

    if (1 > requested_num_threads)
    {
        throw osrm::exception("Number of threads must be a positive number");
    }

    if (!use_shared_memory && option_variables.count("base"))
    {
        return INIT_OK_START_ENGINE;
    }
    if (use_shared_memory && !option_variables.count("base"))
    {
        return INIT_OK_START_ENGINE;
    }
    if (1 > max_locations_distance_table)
    {
        throw osrm::exception("Max location for distance table must be a positive number");
    }
    if (2 > max_locations_map_matching)
    {
        throw osrm::exception("Max location for map matching must be at least two");
    }

    SimpleLogger().Write() << visible_options;
    return INIT_OK_DO_NOT_START_ENGINE;
}
return_code
ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config)
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
        "config,c", boost::program_options::value<boost::filesystem::path>(
                        &extractor_config.config_file_path)->default_value("extractor.ini"),
        "Path to a configuration file.");

    // declare a group of options that will be allowed both on command line and in config file
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()("profile,p",
                                 boost::program_options::value<boost::filesystem::path>(
                                     &extractor_config.profile_path)->default_value("profile.lua"),
                                 "Path to LUA routing profile")(
        "threads,t",
        boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
            ->default_value(tbb::task_scheduler_init::default_num_threads()),
        "Number of threads to use");

    // hidden options, will be allowed both on command line and in config file, but will not be
    // shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()("input,i", boost::program_options::value<boost::filesystem::path>(
                                                &extractor_config.input_path),
                                 "Input file in .osm, .osm.bz2 or .osm.pbf format");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("input", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    boost::program_options::options_description config_file_options;
    config_file_options.add(config_options).add(hidden_options);

    boost::program_options::options_description visible_options(
        boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    try
    {
        boost::program_options::variables_map option_variables;
        boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                          .options(cmdline_options)
                                          .positional(positional_options)
                                          .run(),
                                      option_variables);
        if (option_variables.count("version"))
        {
            SimpleLogger().Write() << g_GIT_DESCRIPTION;
            return return_code::exit;
        }

        if (option_variables.count("help"))
        {
            SimpleLogger().Write() << visible_options;
            return return_code::exit;
        }

        boost::program_options::notify(option_variables);

        // parse config file
        if (boost::filesystem::is_regular_file(extractor_config.config_file_path))
        {
            SimpleLogger().Write()
                << "Reading options from: " << extractor_config.config_file_path.string();
            std::string ini_file_contents =
                read_file_lower_content(extractor_config.config_file_path);
            std::stringstream config_stream(ini_file_contents);
            boost::program_options::store(parse_config_file(config_stream, config_file_options),
                                          option_variables);
            boost::program_options::notify(option_variables);
        }

        if (!option_variables.count("input"))
        {
            SimpleLogger().Write() << visible_options;
            return return_code::exit;
        }
    }
    catch (std::exception &e)
    {
        SimpleLogger().Write(logWARNING) << e.what();
        return return_code::fail;
    }

    return return_code::ok;
}