/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014-2020, Regents of the University of California.
 *
 * This file is part of NDNS (Named Data Networking Domain Name Service).
 * See AUTHORS.md for complete list of NDNS authors and contributors.
 *
 * NDNS 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.
 *
 * NDNS 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
 * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "logger.hpp"
#include "ndns-label.hpp"
#include "mgmt/management-tool.hpp"
#include "util/util.hpp"

#include <boost/program_options.hpp>

#include <iostream>

NDNS_LOG_INIT(NdnsCreateZone);

int
main(int argc, char* argv[])
{
  using std::string;
  using namespace ndn;
  int cacheTtlInt = -1;
  int certTtlInt = -1;
  string zoneStr;
  string parentStr;
  string dskStr;
  string kskStr;
  string dkeyStr;
  string db = ndns::getDefaultDatabaseFile();
  try {
    namespace po = boost::program_options;
    po::variables_map vm;

    po::options_description options("Generic Options");
    options.add_options()
      ("help,h",  "print this help message and exit")
      ("db,b",    po::value<std::string>(&db)->default_value(db), "path to NDNS database file")
      ;

    po::options_description config("Zone Options");
    config.add_options()
      ("cacheTtl,a", po::value<int>(&cacheTtlInt), "Set ttl of records of the zone and its "
        "DSK CERT. Default: 3600 seconds")
      ("certTtl,e", po::value<int>(&certTtlInt), "Set ttl of DSK and KSK certificates. "
        "Default: 365 days")
      ("parent,p", po::value<std::string>(&parentStr), "Set the parent zone of the zone to be "
        "created. Default: the zone's direct parent")
      ("dsk,d", po::value<std::string>(&dskStr), "Set the name of DSK's certificate, "
        "Default: generate new key and certificate")
      ("ksk,k", po::value<std::string>(&kskStr), "Set the name of KSK's certificate, "
        "Default: generate new key and certificate")
      ("dkey,g", po::value<std::string>(&dkeyStr), "Set the name of DKEY's certificate, "
        "Default: generate new key and certificate")
      ;

    options.add(config);

    po::options_description hidden("Hidden Options");
    hidden.add_options()
      ("zone", po::value<string>(&zoneStr), "name of the zone to be created")
      ;
    po::positional_options_description postion;
    postion.add("zone", 1);

    po::options_description cmdline_options;
    cmdline_options.add(options).add(hidden);

    // po::options_description config_file_options;
    // config_file_options.add(config).add(hidden);

    po::parsed_options parsed =
      po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();

    po::store(parsed, vm);
    po::notify(vm);

    if (vm.count("help")) {
      std::cout << "Usage: ndns-create-zone [-b db] zone [-a cacheTtl] [-e certTtl] [-p parent] "
        "[-d dskCert] [-k kskCert] [-g dkeyCert]" << std::endl;
      std::cout << options << std::endl;
      return 0;
    }

    if (vm.count("zone") == 0) {
      std::cerr << "Error: zone must be specified" << std::endl;
      return 1;
    }
  }
  catch (const std::exception& ex) {
    std::cerr << "Parameter Error: " << ex.what() << std::endl;
    return 1;
  }

  try {
    Name zone(zoneStr);
    Name parent(parentStr);
    if (!zone.empty() && parentStr.empty())
      parent = zone.getPrefix(-1);

    Name ksk(kskStr);
    Name dsk(dskStr);
    Name dkey(dkeyStr);

    time::seconds cacheTtl;
    time::seconds certTtl;
    if (cacheTtlInt == -1)
      cacheTtl = ndns::DEFAULT_CACHE_TTL;
    else
      cacheTtl = time::seconds(cacheTtlInt);

    if (certTtlInt == -1)
      certTtl = ndns::DEFAULT_CERT_TTL;
    else
      certTtl = time::seconds(certTtlInt);

    KeyChain keyChain;
    ndn::ndns::ManagementTool tool(db, keyChain);
    ndn::ndns::Zone createdZone = tool.createZone(zone, parent, cacheTtl, certTtl, ksk, dsk, dkey);
    ndn::security::Certificate dkeyCert = tool.getZoneDkey(createdZone);
    NDNS_LOG_INFO("Generated DKEY " << dkeyCert.getName());
    ndn::io::save(dkeyCert, std::cout);
  }
  catch (const std::exception& ex) {
    std::cerr << "Error: " << ex.what() << std::endl;
    return 1;
  }
}
