/* -*- 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 "in-memory-storage.hpp"
#include "in-memory-storage-entry.hpp"

namespace ndn {

const time::milliseconds InMemoryStorage::INFINITE_WINDOW(-1);
const time::milliseconds InMemoryStorage::ZERO_WINDOW(0);

InMemoryStorage::const_iterator::const_iterator(const Data* ptr, const Cache* cache,
                                                Cache::index<byFullName>::type::iterator it)
  : m_ptr(ptr)
  , m_cache(cache)
  , m_it(it)
{
}

InMemoryStorage::const_iterator&
InMemoryStorage::const_iterator::operator++()
{
  m_it++;
  if (m_it != m_cache->get<byFullName>().end()) {
    m_ptr = &((*m_it)->getData());
  }
  else {
    m_ptr = 0;
  }

  return *this;
}

InMemoryStorage::const_iterator
InMemoryStorage::const_iterator::operator++(int)
{
  InMemoryStorage::const_iterator i(*this);
  this->operator++();
  return i;
}

const Data&
InMemoryStorage::const_iterator::operator*()
{
  return *m_ptr;
}

const Data*
InMemoryStorage::const_iterator::operator->()
{
  return m_ptr;
}

bool
InMemoryStorage::const_iterator::operator==(const const_iterator& rhs)
{
  return m_it == rhs.m_it;
}

bool
InMemoryStorage::const_iterator::operator!=(const const_iterator& rhs)
{
  return m_it != rhs.m_it;
}

InMemoryStorage::InMemoryStorage(size_t limit)
  : m_limit(limit)
  , m_nPackets(0)
{
  init();
}

InMemoryStorage::InMemoryStorage(boost::asio::io_service& ioService, size_t limit)
  : m_limit(limit)
  , m_nPackets(0)
{
  m_scheduler = make_unique<Scheduler>(ioService);
  init();
}

void
InMemoryStorage::init()
{
  // TODO consider a more suitable initial value
  m_capacity = 10;

  if (m_limit != std::numeric_limits<size_t>::max() && m_capacity > m_limit) {
    m_capacity = m_limit;
  }

  for (size_t i = 0; i < m_capacity; i++) {
    m_freeEntries.push(new InMemoryStorageEntry());
  }
}

InMemoryStorage::~InMemoryStorage()
{
  // evict all items from cache
  Cache::iterator it = m_cache.begin();
  while (it != m_cache.end()) {
    it = freeEntry(it);
  }

  BOOST_ASSERT(m_freeEntries.size() == m_capacity);

  while (!m_freeEntries.empty()) {
    delete m_freeEntries.top();
    m_freeEntries.pop();
  }
}

void
InMemoryStorage::setCapacity(size_t capacity)
{
  size_t oldCapacity = m_capacity;
  m_capacity = capacity;

  if (size() > m_capacity) {
    ssize_t nAllowedFailures = size() - m_capacity;
    while (size() > m_capacity) {
      if (!evictItem() && --nAllowedFailures < 0) {
        BOOST_THROW_EXCEPTION(Error());
      }
    }
  }

  if (m_capacity >= oldCapacity) {
    for (size_t i = oldCapacity; i < m_capacity; i++) {
      m_freeEntries.push(new InMemoryStorageEntry());
    }
  }
  else {
    for (size_t i = oldCapacity; i > m_capacity; i--) {
      delete m_freeEntries.top();
      m_freeEntries.pop();
    }
  }

  BOOST_ASSERT(size() + m_freeEntries.size() == m_capacity);
}

void
InMemoryStorage::insert(const Data& data, const time::milliseconds& mustBeFreshProcessingWindow)
{
  //check if identical Data/Name already exists
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(data.getFullName());
  if (it != m_cache.get<byFullName>().end())
    return;

  //if full, double the capacity
  bool doesReachLimit = (getLimit() == getCapacity());
  if (isFull() && !doesReachLimit) {
    // note: This is incorrect if 2*capacity overflows, but memory should run out before that
    size_t newCapacity = std::min(2 * getCapacity(), getLimit());
    setCapacity(newCapacity);
  }

  //if full and reach limitation of the capacity, employ replacement policy
  if (isFull() && doesReachLimit) {
    evictItem();
  }

  //insert to cache
  BOOST_ASSERT(m_freeEntries.size() > 0);
  // take entry for the memory pool
  InMemoryStorageEntry* entry = m_freeEntries.top();
  m_freeEntries.pop();
  m_nPackets++;
  entry->setData(data);
  if (m_scheduler != nullptr && mustBeFreshProcessingWindow > ZERO_WINDOW) {
    auto eventId = make_unique<util::scheduler::ScopedEventId>(*m_scheduler);
    *eventId = m_scheduler->scheduleEvent(mustBeFreshProcessingWindow,
                                          bind(&InMemoryStorageEntry::markStale, entry));
    entry->setMarkStaleEventId(std::move(eventId));
  }
  m_cache.insert(entry);

  //let derived class do something with the entry
  afterInsert(entry);
}

shared_ptr<const Data>
InMemoryStorage::find(const Name& name)
{
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().lower_bound(name);

  //if not found, return null
  if (it == m_cache.get<byFullName>().end()) {
    return shared_ptr<const Data>();
  }

  //if the given name is not the prefix of the lower_bound, return null
  if (!name.isPrefixOf((*it)->getFullName())) {
    return shared_ptr<const Data>();
  }

  afterAccess(*it);
  return ((*it)->getData()).shared_from_this();
}

shared_ptr<const Data>
InMemoryStorage::find(const Interest& interest)
{
  //if the interest contains implicit digest, it is possible to directly locate a packet.
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>()
                                                    .find(interest.getName());

  //if a packet is located by its full name, it must be the packet to return.
  if (it != m_cache.get<byFullName>().end()) {
    return ((*it)->getData()).shared_from_this();
  }

  //if the packet is not discovered by last step, either the packet is not in the storage or
  //the interest doesn't contains implicit digest.
  it = m_cache.get<byFullName>().lower_bound(interest.getName());

  if (it == m_cache.get<byFullName>().end()) {
    return shared_ptr<const Data>();
  }

  //to locate the element that has a just smaller name than the interest's
  if (it != m_cache.get<byFullName>().begin())
    it--;

  InMemoryStorageEntry* ret = selectChild(interest, it);
  if (ret != 0) {
    //let derived class do something with the entry
    afterAccess(ret);
    return ret->getData().shared_from_this();
  }
  else {
    return shared_ptr<const Data>();
  }
}

InMemoryStorage::Cache::index<InMemoryStorage::byFullName>::type::iterator
InMemoryStorage::findNextFresh(Cache::index<byFullName>::type::iterator it) const
{
  for (; it != m_cache.get<byFullName>().end(); it++) {
    if ((*it)->isFresh())
      return it;
  }

  return it;
}

InMemoryStorageEntry*
InMemoryStorage::selectChild(const Interest& interest,
                             Cache::index<byFullName>::type::iterator startingPoint) const
{
  BOOST_ASSERT(startingPoint != m_cache.get<byFullName>().end());

  if (startingPoint != m_cache.get<byFullName>().begin())
    {
      BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
    }

  bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
  bool hasRightmostSelector = !hasLeftmostSelector;

  // filter out "stale" data
  if (interest.getMustBeFresh())
    startingPoint = findNextFresh(startingPoint);

  if (startingPoint == m_cache.get<byFullName>().end()) {
    return nullptr;
  }

  if (hasLeftmostSelector)
    {
      if (interest.matchesData((*startingPoint)->getData()))
        {
          return *startingPoint;
        }
    }

  //iterate to the right
  Cache::index<byFullName>::type::iterator rightmost = startingPoint;
  if (startingPoint != m_cache.get<byFullName>().end())
    {
      Cache::index<byFullName>::type::iterator rightmostCandidate = startingPoint;
      Name currentChildPrefix("");

      while (true)
        {
          ++rightmostCandidate;
          // filter out "stale" data
          if (interest.getMustBeFresh())
            rightmostCandidate = findNextFresh(rightmostCandidate);

          bool isInBoundaries = (rightmostCandidate != m_cache.get<byFullName>().end());
          bool isInPrefix = false;
          if (isInBoundaries)
            {
              isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
            }

          if (isInPrefix)
            {
              if (interest.matchesData((*rightmostCandidate)->getData()))
                {
                  if (hasLeftmostSelector)
                    {
                      return *rightmostCandidate;
                    }

                  if (hasRightmostSelector)
                    {
                      // get prefix which is one component longer than Interest name
                      const Name& childPrefix = (*rightmostCandidate)->getFullName()
                                                  .getPrefix(interest.getName().size() + 1);

                      if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
                        {
                          currentChildPrefix = childPrefix;
                          rightmost = rightmostCandidate;
                        }
                    }
                }
            }
          else
            break;
        }
    }

  if (rightmost != startingPoint)
    {
      return *rightmost;
    }

  if (hasRightmostSelector) // if rightmost was not found, try starting point
    {
      if (interest.matchesData((*startingPoint)->getData()))
        {
          return *startingPoint;
        }
    }

  return 0;
}

InMemoryStorage::Cache::iterator
InMemoryStorage::freeEntry(Cache::iterator it)
{
  //push the *empty* entry into mem pool
  (*it)->release();
  m_freeEntries.push(*it);
  m_nPackets--;
  return m_cache.erase(it);
}

void
InMemoryStorage::erase(const Name& prefix, const bool isPrefix)
{
  if (isPrefix) {
    Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().lower_bound(prefix);

    while (it != m_cache.get<byFullName>().end() && prefix.isPrefixOf((*it)->getName())) {
      //let derived class do something with the entry
      beforeErase(*it);
      it = freeEntry(it);
    }
  }
  else {
    Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(prefix);

    if (it == m_cache.get<byFullName>().end())
      return;

    //let derived class do something with the entry
    beforeErase(*it);
    freeEntry(it);
  }

  if (m_freeEntries.size() > (2 * size()))
    setCapacity(getCapacity() / 2);
}

void
InMemoryStorage::eraseImpl(const Name& name)
{
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(name);

  if (it == m_cache.get<byFullName>().end())
    return;

  freeEntry(it);
}

InMemoryStorage::const_iterator
InMemoryStorage::begin() const
{
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().begin();

  return const_iterator(&((*it)->getData()), &m_cache, it);
}

InMemoryStorage::const_iterator
InMemoryStorage::end() const
{
  Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().end();

  return const_iterator(nullptr, &m_cache, it);
}

void
InMemoryStorage::afterInsert(InMemoryStorageEntry* entry)
{
}

void
InMemoryStorage::beforeErase(InMemoryStorageEntry* entry)
{
}

void
InMemoryStorage::afterAccess(InMemoryStorageEntry* entry)
{
}

void
InMemoryStorage::printCache(std::ostream& os) const
{
  //start from the upper layer towards bottom
  const Cache::index<byFullName>::type& cacheIndex = m_cache.get<byFullName>();
  for (Cache::index<byFullName>::type::iterator it = cacheIndex.begin();
       it != cacheIndex.end(); it++)
    os << (*it)->getFullName() << std::endl;
}

} // namespace ndn
