/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (c) 2013-2014,  Regents of the University of California.
 * All rights reserved.
 *
 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 *
 * This file licensed under New BSD License.  See COPYING for detailed information about
 * ndn-cxx library copyright, permissions, and redistribution restrictions.
 *
 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
 */

#ifndef NDNSEC_CERT_INSTALL_HPP
#define NDNSEC_CERT_INSTALL_HPP

#include "ndnsec-util.hpp"


class HttpException : public std::runtime_error
{
public:
  explicit
  HttpException(const std::string& what)
    : std::runtime_error(what)
  {
  }
};

ndn::shared_ptr<ndn::IdentityCertificate>
getCertificateHttp(const std::string& host, const std::string& port, const std::string& path)
{
  using namespace boost::asio::ip;
  tcp::iostream requestStream;

  requestStream.expires_from_now(boost::posix_time::milliseconds(3000));

  requestStream.connect(host, port);
  if (!static_cast<bool>(requestStream))
    {
      throw HttpException("HTTP connection error");
    }
  requestStream << "GET " << path << " HTTP/1.0\r\n";
  requestStream << "Host: " << host << "\r\n";
  requestStream << "Accept: */*\r\n";
  requestStream << "Cache-Control: no-cache\r\n";
  requestStream << "Connection: close\r\n\r\n";
  requestStream.flush();

  std::string statusLine;
  std::getline(requestStream, statusLine);
  if (!static_cast<bool>(requestStream))
    {
      throw HttpException("HTTP communication error");
    }

  std::stringstream responseStream(statusLine);
  std::string httpVersion;
  responseStream >> httpVersion;
  unsigned int statusCode;
  responseStream >> statusCode;
  std::string statusMessage;

  std::getline(responseStream, statusMessage);
  if (!static_cast<bool>(requestStream) || httpVersion.substr(0, 5) != "HTTP/")
    {
      throw HttpException("HTTP communication error");
    }
  if (statusCode != 200)
    {
      throw HttpException("HTTP server error");
    }
  std::string header;
  while (std::getline(requestStream, header) && header != "\r")
    ;

  ndn::OBufferStream os;
  {
    using namespace CryptoPP;
    FileSource ss2(requestStream, true, new Base64Decoder(new FileSink(os)));
  }

  ndn::shared_ptr<ndn::IdentityCertificate> identityCertificate =
    ndn::make_shared<ndn::IdentityCertificate>();
  identityCertificate->wireDecode(ndn::Block(os.buf()));

  return identityCertificate;
}

int
ndnsec_cert_install(int argc, char** argv)
{
  using namespace ndn;
  namespace po = boost::program_options;

  std::string certFileName;
  bool isSystemDefault = true;
  bool isIdentityDefault = false;
  bool isKeyDefault = false;

  po::options_description description("General Usage\n  ndnsec cert-install [-h] [-I|K|N] cert-file\nGeneral options");
  description.add_options()
    ("help,h", "produce help message")
    ("cert-file,f", po::value<std::string>(&certFileName), "file name of the ceritificate, - for stdin. "
                                                      "If starts with http://, will try to fetch "
                                                      "the certificate using HTTP GET request")
    ("identity-default,I", "optional, if specified, the certificate will be set as the default certificate of the identity")
    ("key-default,K", "optional, if specified, the certificate will be set as the default certificate of the key")
    ("no-default,N", "optional, if specified, the certificate will be simply installed")
    ;
  po::positional_options_description p;
  p.add("cert-file", 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::cerr << description << std::endl;
      return 0;
    }

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

  if (vm.count("identity-default") != 0)
    {
      isIdentityDefault = true;
      isSystemDefault = false;
    }
  else if (vm.count("key-default") != 0)
    {
      isKeyDefault = true;
      isSystemDefault = false;
    }
  else if (vm.count("no-default") != 0)
    {
      // noDefault = true;
      isSystemDefault = false;
    }

  shared_ptr<IdentityCertificate> cert;

  if (certFileName.find("http://") == 0)
    {
      std::string host;
      std::string port;
      std::string path;

      size_t pos = 7; // offset of "http://"
      size_t posSlash = certFileName.find("/", pos);

      if (posSlash == std::string::npos)
        throw HttpException("Request line is not correctly formatted");

      size_t posPort = certFileName.find(":", pos);

      if (posPort != std::string::npos && posPort < posSlash) // port is specified
        {
          port = certFileName.substr(posPort + 1, posSlash - posPort - 1);
          host = certFileName.substr(pos, posPort - pos);
        }
      else
        {
          port = "80";
          host = certFileName.substr(pos, posSlash - pos);
        }

      path = certFileName.substr(posSlash, certFileName.size () - posSlash);

      cert = getCertificateHttp(host, port, path);
    }
  else
    {
      cert = getIdentityCertificate(certFileName);
    }

  if (!static_cast<bool>(cert))
    return 1;

  KeyChain keyChain;

  if (isSystemDefault)
    {
      keyChain.addCertificateAsIdentityDefault(*cert);
      Name keyName = cert->getPublicKeyName();
      Name identity = keyName.getSubName(0, keyName.size()-1);
      keyChain.setDefaultIdentity(identity);
    }
  else if (isIdentityDefault)
    {
      keyChain.addCertificateAsIdentityDefault(*cert);
    }
  else if (isKeyDefault)
    {
      keyChain.addCertificateAsKeyDefault(*cert);
    }
  else
    {
      keyChain.addCertificate(*cert);
    }

  std::cerr << "OK: certificate with name ["
            << cert->getName().toUri()
            << "] has been successfully installed"
            << std::endl;

  return 0;
}

#endif //NDNSEC_CERT_INSTALL_HPP
