/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2014,  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 "core/segment-publisher.hpp"

#include "tests/test-common.hpp"
#include "tests/dummy-client-face.hpp"

#include <ndn-cxx/encoding/tlv.hpp>

#include <boost/foreach.hpp>

namespace nfd {
namespace tests {

NFD_LOG_INIT("SegmentPublisherTest");

template<int64_t N=10000>
class TestSegmentPublisher : public SegmentPublisher<DummyClientFace>
{
public:
  TestSegmentPublisher(DummyClientFace& face,
                       const Name& prefix,
                       ndn::KeyChain& keyChain)
    : SegmentPublisher(face, prefix, keyChain)
    , m_totalPayloadLength(0)
  {

  }

  virtual
  ~TestSegmentPublisher()
  {
  }

  uint16_t
  getLimit() const
  {
    return N;
  }

  size_t
  getTotalPayloadLength() const
  {
    return m_totalPayloadLength;
  }

protected:

  virtual size_t
  generate(ndn::EncodingBuffer& outBuffer)
  {
    size_t totalLength = 0;
    for (int64_t i = 0; i < N; i++)
      {
        totalLength += prependNonNegativeIntegerBlock(outBuffer, tlv::Content, i);
      }
    m_totalPayloadLength += totalLength;
    return totalLength;
  }

protected:
  size_t m_totalPayloadLength;
};

template<int64_t N>
class SegmentPublisherFixture : public BaseFixture
{
public:
  SegmentPublisherFixture()
    : m_face(makeDummyClientFace())
    , m_publisher(*m_face, "/localhost/nfd/SegmentPublisherFixture", m_keyChain)
  {
  }

  void
  validate(const Data& data)
  {
    Block payload = data.getContent();
    NFD_LOG_DEBUG("payload size (w/o Content TLV): " << payload.value_size());

    m_buffer.appendByteArray(payload.value(), payload.value_size());

    uint64_t segmentNo = data.getName()[-1].toSegment();
    if (data.getFinalBlockId() != data.getName()[-1])
      {
        return;
      }

    NFD_LOG_DEBUG("got final block: #" << segmentNo);

    // wrap data in a single Content TLV for easy parsing
    m_buffer.prependVarNumber(m_buffer.size());
    m_buffer.prependVarNumber(tlv::Content);

    BOOST_TEST_CHECKPOINT("creating parser");
    ndn::Block parser(m_buffer.buf(), m_buffer.size());
    BOOST_TEST_CHECKPOINT("parsing aggregated response");
    parser.parse();

    BOOST_REQUIRE_EQUAL(parser.elements_size(), m_publisher.getLimit());

    uint64_t expectedNo = m_publisher.getLimit() - 1;
    for (Block::element_const_iterator i = parser.elements_begin();
         i != parser.elements_end();
         ++i)
      {
        uint64_t number = readNonNegativeInteger(*i);
        BOOST_REQUIRE_EQUAL(number, expectedNo);
        --expectedNo;
      }
  }

protected:
  shared_ptr<DummyClientFace> m_face;
  TestSegmentPublisher<N> m_publisher;
  ndn::EncodingBuffer m_buffer;
  ndn::KeyChain m_keyChain;
};

using boost::mpl::int_;
typedef boost::mpl::vector<int_<10000>, int_<100>, int_<10>, int_<0> > DatasetSizes;

BOOST_AUTO_TEST_SUITE(SegmentPublisher)

BOOST_FIXTURE_TEST_CASE_TEMPLATE(Generate, T, DatasetSizes, SegmentPublisherFixture<T::value>)
{
  this->m_publisher.publish();
  this->m_face->processEvents();

  size_t nSegments = this->m_publisher.getTotalPayloadLength() /
                       this->m_publisher.getMaxSegmentSize();
  if (this->m_publisher.getTotalPayloadLength() % this->m_publisher.getMaxSegmentSize() != 0 ||
      nSegments == 0)
    ++nSegments;

  BOOST_CHECK_EQUAL(this->m_face->m_sentDatas.size(), nSegments);
  BOOST_FOREACH(const Data& data, this->m_face->m_sentDatas) {
    this->validate(data);
  }
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace tests
} // namespace nfd
