/* -*- 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 "lsa-segment-storage.hpp"
#include "test-common.hpp"
#include "nlsr.hpp"
#include "name-prefix-list.hpp"
#include "lsa.hpp"

#include <boost/test/unit_test.hpp>

namespace nlsr {
namespace test {

class LsaSegmentStorageFixture : public UnitTestTimeFixture
{
public:
  LsaSegmentStorageFixture()
    : face(m_ioService, m_keyChain)
    , conf(face)
    , nlsr(face, m_keyChain, conf)
    , lsdb(nlsr.m_lsdb)
    , lsaStorage(lsdb.m_lsaStorage)
  {
  }

  std::string
  makeLsaContent()
  {
    ndn::Name s1{"name1"};
    ndn::Name s2{"name2"};
    NamePrefixList npl1{s1, s2};
    NameLsa nameLsa("/ndn/other-site/%C1.Router/other-router", 12,
                    ndn::time::system_clock::now() + ndn::time::seconds(LSA_REFRESH_TIME_DEFAULT), npl1);
    return nameLsa.serialize();
  }

  shared_ptr<ndn::Data>
  makeLsaSegment(const ndn::Name& baseName, uint64_t segmentNo, bool isFinal)
  {
    ndn::Name lsaDataName(baseName);
    lsaDataName.appendSegment(segmentNo);
    auto lsaSegment = make_shared<ndn::Data>(ndn::Name(lsaDataName));
    std::string content = makeLsaContent();
    lsaSegment->setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.length());
    if (isFinal) {
      lsaSegment->setFinalBlock(lsaSegment->getName()[-1]);
    }

    return signData(lsaSegment);
  }

  void
  receiveLsaInterest(const ndn::Name& baseInterestName, uint64_t segmentNo,
                     bool isSegmentZero)
  {
    if (isSegmentZero) {
      lsdb.processInterest(ndn::Name(), ndn::Interest(baseInterestName));
    }
    else {
      ndn::Name nextInterestName(baseInterestName);
      nextInterestName.appendSegment(segmentNo);
      lsdb.processInterest(ndn::Name(), ndn::Interest(nextInterestName));
      advanceClocks(ndn::time::milliseconds(1), 10);
    }
  }

public:
  ndn::util::DummyClientFace face;
  ConfParameter conf;
  Nlsr nlsr;
  Lsdb& lsdb;
  LsaSegmentStorage& lsaStorage;
};

BOOST_FIXTURE_TEST_SUITE(TestLsaSegmentStorage, LsaSegmentStorageFixture)

BOOST_AUTO_TEST_CASE(Basic)
{
  ndn::Name lsaInterestName("/ndn/NLSR/LSA/other-site/%C1.Router/other-router/NAME");
  lsaInterestName.appendNumber(12);

  ndn::Name lsaDataName(lsaInterestName);
  lsaDataName.appendVersion();

  for (uint64_t segmentNo = 0; segmentNo < 4; ++segmentNo) {
    auto lsaData = makeLsaSegment(lsaDataName, segmentNo, segmentNo == 4);
    lsaStorage.afterFetcherSignalEmitted(*lsaData);
  }

  // receive interest for other-router's LSA that is stored in this router's storage
  for (uint64_t segmentNo = 0; segmentNo < 4; ++segmentNo) {
    receiveLsaInterest(lsaInterestName, segmentNo, segmentNo == 0);
  }

  // 4 data segments should be sent in response to 4 interests
  BOOST_CHECK_EQUAL(face.sentData.size(), 4);
}

BOOST_AUTO_TEST_CASE(DeleteOldLsa)
{
  ndn::Name lsaDataName("/ndn/NLSR/LSA/other-site/%C1.Router/other-router/NAME");
  uint64_t segmentNo = 0;

  uint64_t oldSeqNo = 12;
  ndn::Name oldLsaDataName(lsaDataName);
  oldLsaDataName.appendNumber(oldSeqNo);
  oldLsaDataName.appendVersion();

  auto oldLsaData = makeLsaSegment(oldLsaDataName, segmentNo, true);
  lsaStorage.afterFetcherSignalEmitted(*oldLsaData);
  advanceClocks(ndn::time::milliseconds(1), 10);

  uint64_t newSeqNo = 13;
  ndn::Name newLsaDataName(lsaDataName);
  newLsaDataName.appendNumber(newSeqNo);
  newLsaDataName.appendVersion();

  auto newLsaData = makeLsaSegment(newLsaDataName, segmentNo, true);
  lsaStorage.afterFetcherSignalEmitted(*newLsaData);
  advanceClocks(ndn::time::milliseconds(1), 10);

  ndn::Name lsaInterestName(lsaDataName);

  ndn::Name oldLsaInterestName(lsaInterestName);
  oldLsaInterestName.appendNumber(oldSeqNo);
  receiveLsaInterest(oldLsaInterestName, segmentNo, true);

  advanceClocks(ndn::time::milliseconds(1), 10);

  BOOST_CHECK_EQUAL(face.sentData.size(), 0);

  ndn::Name newLsaInterestName(lsaInterestName);
  newLsaInterestName.appendNumber(newSeqNo);
  receiveLsaInterest(newLsaInterestName, segmentNo, true);

  advanceClocks(ndn::time::milliseconds(1), 10);

  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
}

BOOST_AUTO_TEST_CASE(ScheduledDeletion)
{
  ndn::Name lsaInterestName("/ndn/NLSR/LSA/other-site/%C1.Router/other-router/NAME");
  lsaInterestName.appendNumber(12);

  ndn::Name lsaDataName(lsaInterestName);
  lsaDataName.appendVersion();

  auto lsaData = makeLsaSegment(lsaDataName, 0, true);
  lsaStorage.afterFetcherSignalEmitted(*lsaData);

  BOOST_CHECK(lsaStorage.getLsaSegment(ndn::Interest(lsaInterestName)) != nullptr);

  // Make sure it was not deleted earlier somehow
  advanceClocks(ndn::time::seconds(100), 10);
  BOOST_CHECK(lsaStorage.getLsaSegment(ndn::Interest(lsaInterestName)) != nullptr);

  advanceClocks(ndn::time::seconds(LSA_REFRESH_TIME_DEFAULT), 10);

  BOOST_CHECK(lsaStorage.getLsaSegment(ndn::Interest(lsaInterestName)) == nullptr);
}

BOOST_AUTO_TEST_SUITE_END() // TestLsaSegmentStorage

} // namespace test
} // namespace nlsr
