/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2013-2017 Regents of the University of California.
 *
 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
 *
 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * ndn-cxx library 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 Lesser General Public License for more details.
 *
 * You should have received copies of the GNU General Public License and GNU Lesser
 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 */

#include "ndnsec.hpp"
#include "util.hpp"

namespace ndn {
namespace ndnsec {

int
ndnsec_cert_gen(int argc, char** argv)
{
  using boost::tokenizer;
  using boost::escaped_list_separator;

  namespace po = boost::program_options;

  security::v1::KeyChain keyChain;

  std::string notBeforeStr;
  std::string notAfterStr;
  std::string subjectName;
  std::string requestFile("-");
  Name signId;
  std::string subjectInfo;
  std::vector<std::string> signedInfo;
  Name certPrefix = security::v1::KeyChain::DEFAULT_PREFIX; // to avoid displaying the default value

  po::options_description description(
    "General Usage\n"
    "  ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] "
        "[-s sign-id] [-p cert-prefix] request\n"
    "General options");

  description.add_options()
    ("help,h", "produce help message")
    ("not-before,S",   po::value<std::string>(&notBeforeStr),
                       "certificate starting date, YYYYMMDDhhmmss (default: now)")
    ("not-after,E",    po::value<std::string>(&notAfterStr),
                       "certificate ending date, YYYYMMDDhhmmss (default: now + 365 days)")
    ("subject-name,N", po::value<std::string>(&subjectName),
                       "subject name")
    ("subject-info,I", po::value<std::string>(&subjectInfo),
                       "(deprecated, uses 'signed-info') subject info, pairs of OID and string "
                       " description: \"2.5.4.10 'University of California, Los Angeles'\"")
    ("signed-info",    po::value<std::vector<std::string> >(&signedInfo),
                       "a pair of OID and string (must be separated by a single space), e.g., "
                       "\"2.5.4.10 University of California, Los Angeles\". "
                       "May be repeated multiple times")
    ("sign-id,s",      po::value<Name>(&signId)->default_value(keyChain.getDefaultIdentity()),
                       "signing identity")
    ("cert-prefix,p",  po::value<Name>(&certPrefix),
                       "cert prefix, which is the part of certificate name before "
                       "KEY component")
    ("request,r",      po::value<std::string>(&requestFile)->default_value("-"),
                       "request file name, - for stdin")
    ;

  po::positional_options_description p;
  p.add("request", 1);

  po::variables_map vm;
  try {
    po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
    po::notify(vm);
  }
  catch (const std::exception& e) {
    std::cerr << "ERROR: " << e.what() << std::endl;
    return 1;
  }

  if (vm.count("help") != 0) {
    std::cout << description << std::endl;
    return 0;
  }

  if (vm.count("subject-name") == 0) {
    std::cerr << "ERROR: subject name must be specified" << std::endl
              << std::endl
              << description << std::endl;
    return 1;
  }

  std::vector<security::v1::CertificateSubjectDescription> subjectDescription;
  subjectDescription.push_back(security::v1::CertificateSubjectDescription(oid::ATTRIBUTE_NAME, subjectName));

  // 'subjectInfo' is deprecated and the following block will be removed eventually
  tokenizer<escaped_list_separator<char>> subjectInfoItems(subjectInfo,
                                                           escaped_list_separator<char>("\\", " \t",
                                                                                        "'\""));

  tokenizer<escaped_list_separator<char>>::iterator it = subjectInfoItems.begin();

  while (it != subjectInfoItems.end()) {
    std::string oid = *it;

    it++;
    if (it == subjectInfoItems.end()) {
      std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
      return 1;
    }

    std::string value = *it;

    subjectDescription.push_back(security::v1::CertificateSubjectDescription(Oid(oid), value));

    it++;
  }

  // new 'signedInfo' processing
  for (std::vector<std::string>::const_iterator info = signedInfo.begin(); info != signedInfo.end();
       ++info) {
    size_t pos = info->find(" ");
    if (pos == std::string::npos) {
      std::cerr << "ERROR: incorrectly formatted signed info block [" << *info << "]" << std::endl;
      return 1;
    }
    Oid oid(info->substr(0, pos));
    std::string value = info->substr(pos + 1);

    subjectDescription.push_back(security::v1::CertificateSubjectDescription(oid, value));
  }

  time::system_clock::TimePoint notBefore;
  time::system_clock::TimePoint notAfter;

  if (vm.count("not-before") == 0) {
    notBefore = time::system_clock::now();
  }
  else {
    notBefore = time::fromIsoString(notBeforeStr.substr(0, 8) + "T" + notBeforeStr.substr(8, 6));
  }

  if (vm.count("not-after") == 0) {
    notAfter = notBefore + time::days(365);
  }
  else {
    notAfter = time::fromIsoString(notAfterStr.substr(0, 8) + "T" + notAfterStr.substr(8, 6));

    if (notAfter < notBefore) {
      std::cerr << "ERROR: not-before cannot be later than not-after" << std::endl
                << std::endl
                << description << std::endl;
      return 1;
    }
  }

  if (vm.count("request") == 0) {
    std::cerr << "ERROR: request file must be specified" << std::endl
              << std::endl
              << description << std::endl;
    return 1;
  }

  shared_ptr<security::v1::IdentityCertificate> selfSignedCertificate = getIdentityCertificate(requestFile);

  if (selfSignedCertificate == nullptr) {
    std::cerr << "ERROR: input error" << std::endl;
    return 1;
  }

  Name keyName = selfSignedCertificate->getPublicKeyName();

  shared_ptr<security::v1::IdentityCertificate> certificate =
    keyChain.prepareUnsignedIdentityCertificate(keyName, selfSignedCertificate->getPublicKeyInfo(),
                                                signId, notBefore, notAfter, subjectDescription,
                                                certPrefix);

  if (certificate == nullptr) {
    std::cerr << "ERROR: key name is not formated correctly or does not match certificate name"
              << std::endl;
    return 1;
  }

  keyChain.createIdentity(signId);
  Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signId);
  keyChain.sign(*certificate,
                security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT,
                                      signingCertificateName));

  Block wire = certificate->wireEncode();

  namespace t = security::transform;
  try {
    t::bufferSource(wire.wire(), wire.size()) >> t::base64Encode(true) >> t::streamSink(std::cout);
  }
  catch (const security::transform::Error& e) {
    std::cerr << "ERROR: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}

} // namespace ndnsec
} // namespace ndn
