/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014-2019,  Regents of the University of California,
 *                           Arizona Board of Regents,
 *                           Colorado State University,
 *                           University Pierre & Marie Curie, Sorbonne University,
 *                           Washington University in St. Louis,
 *                           Beijing Institute of Technology,
 *                           The University of Memphis.
 *
 * This file is part of NFD (Named Data Networking Forwarding Daemon).
 * See AUTHORS.md for complete list of NFD authors and contributors.
 *
 * NFD 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.
 *
 * NFD 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
 * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "tests/test-common.hpp"

#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>

namespace nfd {
namespace tests {

shared_ptr<Interest>
makeInterest(const Name& name, uint32_t nonce)
{
  auto interest = make_shared<Interest>(name);
  if (nonce != 0) {
    interest->setNonce(nonce);
  }
  return interest;
}

shared_ptr<Data>
makeData(const Name& name)
{
  auto data = make_shared<Data>(name);
  return signData(data);
}

Data&
signData(Data& data)
{
  ndn::SignatureSha256WithRsa fakeSignature;
  fakeSignature.setValue(ndn::encoding::makeEmptyBlock(tlv::SignatureValue));
  data.setSignature(fakeSignature);
  data.wireEncode();

  return data;
}

lp::Nack
makeNack(Interest interest, lp::NackReason reason)
{
  lp::Nack nack(std::move(interest));
  nack.setReason(reason);
  return nack;
}

lp::Nack
makeNack(const Name& name, uint32_t nonce, lp::NackReason reason)
{
  Interest interest(name);
  interest.setNonce(nonce);
  return makeNack(std::move(interest), reason);
}

ndn::PrefixAnnouncement
makePrefixAnn(const Name& announcedName, time::milliseconds expiration,
              optional<ndn::security::ValidityPeriod> validity)
{
  ndn::PrefixAnnouncement pa;
  pa.setAnnouncedName(announcedName);
  pa.setExpiration(expiration);
  pa.setValidityPeriod(validity);
  return pa;
}

ndn::PrefixAnnouncement
makePrefixAnn(const Name& announcedName, time::milliseconds expiration,
              std::pair<time::seconds, time::seconds> validityFromNow)
{
  auto now = time::system_clock::now();
  return makePrefixAnn(announcedName, expiration,
    ndn::security::ValidityPeriod(now + validityFromNow.first, now + validityFromNow.second));
}

ndn::PrefixAnnouncement
signPrefixAnn(ndn::PrefixAnnouncement&& pa, ndn::KeyChain& keyChain,
              const ndn::security::SigningInfo& si, optional<uint64_t> version)
{
  pa.toData(keyChain, si, version);
  return std::move(pa);
}

} // namespace tests
} // namespace nfd
