/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2011 University of California, Los Angeles
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
 */

#ifndef NDN_CONTENT_STORE_IMPL_H_
#define NDN_CONTENT_STORE_IMPL_H_

#include "ns3/ndnSIM/model/ndn-common.hpp"

#include "ndn-content-store.hpp"

#include "ns3/packet.h"
#include <boost/foreach.hpp>

#include "ns3/log.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"

#include "../../utils/trie/trie-with-policy.hpp"

namespace ns3 {
namespace ndn {
namespace cs {

/**
 * @ingroup ndn-cs
 * @brief Cache entry implementation with additional references to the base container
 */
template<class CS>
class EntryImpl : public Entry {
public:
  typedef Entry base_type;

public:
  EntryImpl(Ptr<ContentStore> cs, shared_ptr<const Data> data)
    : Entry(cs, data)
    , item_(0)
  {
  }

  void
  SetTrie(typename CS::super::iterator item)
  {
    item_ = item;
  }

  typename CS::super::iterator
  to_iterator()
  {
    return item_;
  }
  typename CS::super::const_iterator
  to_iterator() const
  {
    return item_;
  }

private:
  typename CS::super::iterator item_;
};

/**
 * @ingroup ndn-cs
 * @brief Base implementation of NDN content store
 */
template<class Policy>
class ContentStoreImpl
  : public ContentStore,
    protected ndnSIM::
      trie_with_policy<Name,
                       ndnSIM::smart_pointer_payload_traits<EntryImpl<ContentStoreImpl<Policy>>,
                                                            Entry>,
                       Policy> {
public:
  typedef ndnSIM::
    trie_with_policy<Name, ndnSIM::smart_pointer_payload_traits<EntryImpl<ContentStoreImpl<Policy>>,
                                                                Entry>,
                     Policy> super;

  typedef EntryImpl<ContentStoreImpl<Policy>> entry;

  static TypeId
  GetTypeId();

  ContentStoreImpl(){};
  virtual ~ContentStoreImpl(){};

  // from ContentStore

  virtual inline shared_ptr<Data>
  Lookup(shared_ptr<const Interest> interest);

  virtual inline bool
  Add(shared_ptr<const Data> data);

  // virtual bool
  // Remove (shared_ptr<Interest> header);

  virtual inline void
  Print(std::ostream& os) const;

  virtual uint32_t
  GetSize() const;

  virtual Ptr<Entry>
  Begin();

  virtual Ptr<Entry>
  End();

  virtual Ptr<Entry> Next(Ptr<Entry>);

  const typename super::policy_container&
  GetPolicy() const
  {
    return super::getPolicy();
  }

  typename super::policy_container&
  GetPolicy()
  {
    return super::getPolicy();
  }

private:
  void
  SetMaxSize(uint32_t maxSize);

  uint32_t
  GetMaxSize() const;

private:
  static LogComponent g_log; ///< @brief Logging variable

  /// @brief trace of for entry additions (fired every time entry is successfully added to the
  /// cache): first parameter is pointer to the CS entry
  TracedCallback<Ptr<const Entry>> m_didAddEntry;
};

//////////////////////////////////////////
////////// Implementation ////////////////
//////////////////////////////////////////

template<class Policy>
LogComponent
  ContentStoreImpl<Policy>::g_log = LogComponent(("ndn.cs." + Policy::GetName()).c_str());

template<class Policy>
TypeId
ContentStoreImpl<Policy>::GetTypeId()
{
  static TypeId tid =
    TypeId(("ns3::ndn::cs::" + Policy::GetName()).c_str())
      .SetGroupName("Ndn")
      .SetParent<ContentStore>()
      .AddConstructor<ContentStoreImpl<Policy>>()
      .AddAttribute("MaxSize",
                    "Set maximum number of entries in ContentStore. If 0, limit is not enforced",
                    StringValue("100"), MakeUintegerAccessor(&ContentStoreImpl<Policy>::GetMaxSize,
                                                             &ContentStoreImpl<Policy>::SetMaxSize),
                    MakeUintegerChecker<uint32_t>())

      .AddTraceSource("DidAddEntry",
                      "Trace fired every time entry is successfully added to the cache",
                      MakeTraceSourceAccessor(&ContentStoreImpl<Policy>::m_didAddEntry));

  return tid;
}

struct isNotExcluded {
  inline isNotExcluded(const Exclude& exclude)
    : m_exclude(exclude)
  {
  }

  bool
  operator()(const name::Component& comp) const
  {
    return !m_exclude.isExcluded(comp);
  }

private:
  const Exclude& m_exclude;
};

template<class Policy>
shared_ptr<Data>
ContentStoreImpl<Policy>::Lookup(shared_ptr<const Interest> interest)
{
  NS_LOG_FUNCTION(this << interest->getName());

  typename super::const_iterator node;
  if (interest->getExclude().empty()) {
    node = this->deepest_prefix_match(interest->getName());
  }
  else {
    node = this->deepest_prefix_match_if_next_level(interest->getName(),
                                                    isNotExcluded(interest->getExclude()));
  }

  if (node != this->end()) {
    this->m_cacheHitsTrace(interest, node->payload()->GetData());

    shared_ptr<Data> copy = make_shared<Data>(*node->payload()->GetData());
    return copy;
  }
  else {
    this->m_cacheMissesTrace(interest);
    return 0;
  }
}

template<class Policy>
bool
ContentStoreImpl<Policy>::Add(shared_ptr<const Data> data)
{
  NS_LOG_FUNCTION(this << data->getName());

  Ptr<entry> newEntry = Create<entry>(this, data);
  std::pair<typename super::iterator, bool> result = super::insert(data->getName(), newEntry);

  if (result.first != super::end()) {
    if (result.second) {
      newEntry->SetTrie(result.first);

      m_didAddEntry(newEntry);
      return true;
    }
    else {
      // should we do anything?
      // update payload? add new payload?
      return false;
    }
  }
  else
    return false; // cannot insert entry
}

template<class Policy>
void
ContentStoreImpl<Policy>::Print(std::ostream& os) const
{
  for (typename super::policy_container::const_iterator item = this->getPolicy().begin();
       item != this->getPolicy().end(); item++) {
    os << item->payload ()->GetName () << std::endl;
  }
}

template<class Policy>
void
ContentStoreImpl<Policy>::SetMaxSize(uint32_t maxSize)
{
  this->getPolicy().set_max_size(maxSize);
}

template<class Policy>
uint32_t
ContentStoreImpl<Policy>::GetMaxSize() const
{
  return this->getPolicy().get_max_size();
}

template<class Policy>
uint32_t
ContentStoreImpl<Policy>::GetSize() const
{
  return this->getPolicy().size();
}

template<class Policy>
Ptr<Entry>
ContentStoreImpl<Policy>::Begin()
{
  typename super::parent_trie::recursive_iterator item(super::getTrie()), end(0);
  for (; item != end; item++) {
    if (item->payload() == 0)
      continue;
    break;
  }

  if (item == end)
    return End();
  else
    return item->payload();
}

template<class Policy>
Ptr<Entry>
ContentStoreImpl<Policy>::End()
{
  return 0;
}

template<class Policy>
Ptr<Entry>
ContentStoreImpl<Policy>::Next(Ptr<Entry> from)
{
  if (from == 0)
    return 0;

  typename super::parent_trie::recursive_iterator item(*StaticCast<entry>(from)->to_iterator()),
    end(0);

  for (item++; item != end; item++) {
    if (item->payload() == 0)
      continue;
    break;
  }

  if (item == end)
    return End();
  else
    return item->payload();
}

} // namespace cs
} // namespace ndn
} // namespace ns3

#endif // NDN_CONTENT_STORE_IMPL_H_
