/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2015-2019, Arizona Board of Regents.
 *
 * This file is part of ndn-tools (Named Data Networking Essential Tools).
 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
 *
 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * ndn-tools, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Eric Newberry <enewberry@email.arizona.edu>
 * @author Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
 */

#include "core/common.hpp"
#include "core/version.hpp"

#include "ping-server.hpp"
#include "tracer.hpp"

namespace ndn {
namespace ping {
namespace server {

namespace po = boost::program_options;

class Runner : noncopyable
{
public:
  explicit
  Runner(const Options& options)
    : m_options(options)
    , m_pingServer(m_face, m_keyChain, options)
    , m_tracer(m_pingServer, options)
    , m_signalSet(m_face.getIoService(), SIGINT)
  {
    m_pingServer.afterFinish.connect([this] {
      m_pingServer.stop();
      m_signalSet.cancel();
    });

    m_signalSet.async_wait([this] (const auto& ec, auto) {
      if (ec != boost::asio::error::operation_aborted) {
        m_pingServer.stop();
      }
    });
  }

  int
  run()
  {
    std::cout << "PING SERVER " << m_options.prefix << std::endl;

    try {
      m_pingServer.start();
      m_face.processEvents();
    }
    catch (const std::exception& e) {
      std::cerr << "ERROR: " << e.what() << std::endl;
      return 1;
    }

    std::cout << "\n--- " << m_options.prefix << " ping server statistics ---\n"
              << m_pingServer.getNPings() << " packets processed" << std::endl;
    return 0;
  }

private:
  const Options& m_options;

  Face m_face;
  KeyChain m_keyChain;
  PingServer m_pingServer;
  Tracer m_tracer;

  boost::asio::signal_set m_signalSet;
};

static void
usage(std::ostream& os, const std::string& programName, const po::options_description& options)
{
  os << "Usage: " << programName << " [options] <prefix>\n"
     << "\n"
     << "Starts a NDN ping server that responds to Interests under name ndn:<prefix>/ping\n"
     << "\n"
     << options;
}

static int
main(int argc, char* argv[])
{
  Options options;
  std::string prefix;
  auto nMaxPings = static_cast<std::make_signed_t<size_t>>(options.nMaxPings);
  auto payloadSize = static_cast<std::make_signed_t<size_t>>(options.payloadSize);

  po::options_description visibleDesc("Options");
  visibleDesc.add_options()
    ("help,h",      "print this help message and exit")
    ("freshness,f", po::value<time::milliseconds::rep>()->default_value(options.freshnessPeriod.count()),
                    "FreshnessPeriod of the ping response, in milliseconds")
    ("satisfy,p",   po::value(&nMaxPings)->default_value(nMaxPings),
                    "maximum number of pings to satisfy (0 = no limit)")
    ("size,s",      po::value(&payloadSize)->default_value(payloadSize),
                    "size of response payload")
    ("timestamp,t", po::bool_switch(&options.wantTimestamp),
                    "prepend a timestamp to each log message")
    ("quiet,q",     po::bool_switch(&options.wantQuiet),
                    "do not print a log message each time a ping packet is received")
    ("version,V",   "print program version and exit")
    ;

  po::options_description hiddenDesc;
  hiddenDesc.add_options()
    ("prefix", po::value<std::string>(&prefix));

  po::options_description deprecatedDesc;
  deprecatedDesc.add_options()
    ("_deprecated_freshness_,x", po::value<time::milliseconds::rep>())
    ;

  po::options_description optDesc;
  optDesc.add(visibleDesc).add(hiddenDesc).add(deprecatedDesc);

  po::positional_options_description posDesc;
  posDesc.add("prefix", -1);

  po::variables_map vm;
  try {
    po::store(po::command_line_parser(argc, argv).options(optDesc).positional(posDesc).run(), vm);
    po::notify(vm);
  }
  catch (const po::error& e) {
    std::cerr << "ERROR: " << e.what() << "\n\n";
    usage(std::cerr, argv[0], visibleDesc);
    return 2;
  }
  catch (const boost::bad_any_cast& e) {
    std::cerr << "ERROR: " << e.what() << "\n\n";
    usage(std::cerr, argv[0], visibleDesc);
    return 2;
  }

  if (vm.count("_deprecated_freshness_") > 0) {
    std::cerr << "WARNING: short option '-x' is deprecated and will be removed in the near "
                 "future. Please use '-f' or the long form '--freshness'." << std::endl;
  }

  if (vm.count("help") > 0) {
    usage(std::cout, argv[0], visibleDesc);
    return 0;
  }

  if (vm.count("version") > 0) {
    std::cout << "ndnpingserver " << tools::VERSION << std::endl;
    return 0;
  }

  if (prefix.empty()) {
    std::cerr << "ERROR: no name prefix specified\n\n";
    usage(std::cerr, argv[0], visibleDesc);
    return 2;
  }
  options.prefix = prefix;

  options.freshnessPeriod = time::milliseconds(vm["freshness"].as<time::milliseconds::rep>());
  if (vm.count("_deprecated_freshness_") > 0) {
    options.freshnessPeriod = time::milliseconds(vm["_deprecated_freshness_"].as<time::milliseconds::rep>());
  }
  if (options.freshnessPeriod < 0_ms) {
    std::cerr << "ERROR: FreshnessPeriod cannot be negative" << std::endl;
    return 2;
  }

  if (nMaxPings < 0) {
    std::cerr << "ERROR: maximum number of pings to satisfy cannot be negative" << std::endl;
    return 2;
  }
  options.nMaxPings = static_cast<size_t>(nMaxPings);

  if (payloadSize < 0) {
    std::cerr << "ERROR: payload size cannot be negative" << std::endl;
    return 2;
  }
  options.payloadSize = static_cast<size_t>(payloadSize);

  return Runner(options).run();
}

} // namespace server
} // namespace ping
} // namespace ndn

int
main(int argc, char* argv[])
{
  return ndn::ping::server::main(argc, argv);
}
