/* -*- 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 "cs.hpp"
#include "cs-entry.hpp"
#include "core/logger.hpp"
#include <numeric>

NFD_LOG_INIT("ContentStore");

namespace nfd {
namespace cs {

Cs::Cs(size_t nMaxPackets)
  : m_limit(nMaxPackets)
{
  BOOST_ASSERT(nMaxPackets > 0);
}

Cs::~Cs()
{
  // It's necessary to put this empty destructor in cs.cpp,
  // because cs::Entry has incomplete type in cs.hpp.
}

void
Cs::setLimit(size_t nMaxPackets)
{
  BOOST_ASSERT(nMaxPackets > 0);
  m_limit = nMaxPackets;
  this->evict();
}

size_t
Cs::size() const
{
  return m_table.size();
}

bool
Cs::insert(const Data& data, bool isUnsolicited)
{
  NFD_LOG_DEBUG("insert " << data.getFullName());

  bool isNewEntry = false; TableIt it;
  // use .insert because gcc46 does not support .emplace
  std::tie(it, isNewEntry) = m_table.insert(Entry(data.shared_from_this(), isUnsolicited));
  Entry& entry = const_cast<Entry&>(*it);

  if (!isNewEntry) { // existing entry
    this->detachQueue(it);
    // XXX This doesn't forbid unsolicited Data from refreshing a solicited entry.
    if (entry.isUnsolicited() && !isUnsolicited) {
      entry.unsetUnsolicited();
    }
  }
  entry.refresh();
  this->attachQueue(it);

  // check there are same amount of entries in the table and in queues
  BOOST_ASSERT(m_table.size() == std::accumulate(m_queues, m_queues + QUEUE_UBOUND, 0U,
      [] (size_t sum, const Queue queue) { return sum + queue.size(); }));

  this->evict(); // XXX The new entry could be evicted, but it shouldn't matter.

  return true;
}

bool
Cs::isNewRightmostCandidate(const Name& prefix, TableIt a, TableIt b)
{
  if (a->getFullName().size() == prefix.size()) {
    return true;
  }
  return b->getFullName().at(prefix.size()) > a->getFullName().at(prefix.size());
}

const Data*
Cs::find(const Interest& interest) const
{
  const Name& prefix = interest.getName();
  bool isRightmost = interest.getChildSelector() == 1;
  NFD_LOG_DEBUG("find " << prefix << (isRightmost ? " R" : " L"));
  TableIt rightmostCandidate = m_table.end();

  TableIt left = m_table.lower_bound(prefix);
  TableIt right = m_table.end();
  if (prefix.size() > 0) {
    right = m_table.lower_bound(prefix.getSuccessor());
  }
  for (TableIt it = left; it != right; ++it) {
    const Entry& entry = *it;
    if (!entry.canSatisfy(interest)) {
      NFD_LOG_TRACE("cannotSatisfy " << entry.getFullName());
      continue;
    }
    NFD_LOG_TRACE("canSatisfy " << entry.getFullName());
    if (!isRightmost) {
      return entry.getData().get();
    }

    if (rightmostCandidate == m_table.end() ||
        isNewRightmostCandidate(prefix, rightmostCandidate, it)) {
      NFD_LOG_TRACE("rightmostCandidate=" << entry.getFullName());
      rightmostCandidate = it;
    }
  }
  if (isRightmost) {
    return rightmostCandidate == m_table.end() ? nullptr :
                                 rightmostCandidate->getData().get();
  }
  return nullptr;
}

void
Cs::attachQueue(TableIt it)
{
  Entry& entry = const_cast<Entry&>(*it);

  if (entry.queueType != QUEUE_NONE) {
    this->detachQueue(it);
  }

  if (entry.isUnsolicited()) {
    entry.queueType = QUEUE_UNSOLICITED;
  }
  else if (entry.isStale()) {
    entry.queueType = QUEUE_STALE;
  }
  else {
    entry.queueType = QUEUE_FIFO;

    if (entry.canStale()) {
      entry.moveStaleEvent = scheduler::schedule(entry.getData()->getFreshnessPeriod(),
                             bind(&Cs::moveToStaleQueue, this, it));
    }
  }

  Queue& queue = m_queues[entry.queueType];
  entry.queueIt = queue.insert(queue.end(), it);
}

void
Cs::detachQueue(TableIt it)
{
  Entry& entry = const_cast<Entry&>(*it);

  BOOST_ASSERT(entry.queueType != QUEUE_NONE);

  if (entry.queueType == QUEUE_FIFO) {
    scheduler::cancel(entry.moveStaleEvent);
  }

  m_queues[entry.queueType].erase(entry.queueIt);
  entry.queueType = QUEUE_NONE;
}

void
Cs::moveToStaleQueue(TableIt it)
{
  Entry& entry = const_cast<Entry&>(*it);

  BOOST_ASSERT(entry.queueType == QUEUE_FIFO);
  m_queues[QUEUE_FIFO].erase(entry.queueIt);

  entry.queueType = QUEUE_STALE;
  Queue& queue = m_queues[QUEUE_STALE];
  entry.queueIt = queue.insert(queue.end(), it);
}

std::tuple<Cs::TableIt, std::string>
Cs::evictPick()
{
  if (!m_queues[QUEUE_UNSOLICITED].empty()) {
    return std::make_tuple(m_queues[QUEUE_UNSOLICITED].front(), "unsolicited");
  }
  if (!m_queues[QUEUE_STALE].empty()) {
    return std::make_tuple(m_queues[QUEUE_STALE].front(), "stale");
  }
  if (!m_queues[QUEUE_FIFO].empty()) {
    return std::make_tuple(m_queues[QUEUE_FIFO].front(), "fifo");
  }

  BOOST_ASSERT(false);
  return std::make_tuple(m_table.end(), "error");
}


void
Cs::evict()
{
  while (this->size() > m_limit) {
    TableIt it; std::string reason;
    std::tie(it, reason) = this->evictPick();

    NFD_LOG_DEBUG("evict " << it->getFullName() << " " << reason);
    this->detachQueue(it);
    m_table.erase(it);
  }
}

void
Cs::dump()
{
  NFD_LOG_DEBUG("dump table");
  for (const Entry& entry : m_table) {
    NFD_LOG_TRACE(entry.getFullName());
  }
}

} // namespace cs
} // namespace nfd
