/* -*-  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 TRIE_WITH_POLICY_H_
#define TRIE_WITH_POLICY_H_

#include "trie.hpp"

namespace ns3 {
namespace ndn {
namespace ndnSIM {

template<typename FullKey,
         typename PayloadTraits,
         typename PolicyTraits
         >
class trie_with_policy
{
public:
  typedef trie< FullKey,
                PayloadTraits,
                typename PolicyTraits::policy_hook_type > parent_trie;

  typedef typename parent_trie::iterator iterator;
  typedef typename parent_trie::const_iterator const_iterator;

  typedef typename PolicyTraits::template policy<
    trie_with_policy<FullKey, PayloadTraits, PolicyTraits>,
    parent_trie,
    typename PolicyTraits::template container_hook<parent_trie>::type >::type policy_container;

  inline
  trie_with_policy (size_t bucketSize = 1, size_t bucketIncrement = 1)
    : trie_ (name::Component (), bucketSize, bucketIncrement)
    , policy_ (*this)
  {
  }

  inline std::pair< iterator, bool >
  insert (const FullKey &key, typename PayloadTraits::insert_type payload)
  {
    std::pair<iterator, bool> item =
      trie_.insert (key, payload);

    if (item.second) // real insert
      {
        bool ok = policy_.insert (s_iterator_to (item.first));
        if (!ok)
          {
            item.first->erase (); // cannot insert
            return std::make_pair (end (), false);
          }
      }
    else
      {
        return std::make_pair (s_iterator_to (item.first), false);
      }

    return item;
  }

  inline void
  erase (const FullKey &key)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);

    if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
      return; // nothing to invalidate

    erase (lastItem);
  }

  inline void
  erase (iterator node)
  {
    if (node == end ()) return;

    policy_.erase (s_iterator_to (node));
    node->erase (); // will do cleanup here
  }

  inline void
  clear ()
  {
    policy_.clear ();
    trie_.clear ();
  }

  template<typename Modifier>
  bool
  modify (iterator position, Modifier mod)
  {
    if (position == end ()) return false;
    if (position->payload () == PayloadTraits::empty_payload) return false;

    mod (*position->payload ());
    policy_.update (position);
    return true;
  }

  /**
   * @brief Find a node that has the exact match with the key
   */
  inline iterator
  find_exact (const FullKey &key)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);

    if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
      return end ();

    return lastItem;
  }

  /**
   * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
   */
  inline iterator
  longest_prefix_match (const FullKey &key)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
    if (foundItem != trie_.end ())
      {
        policy_.lookup (s_iterator_to (foundItem));
      }
    return foundItem;
  }

  /**
   * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
   */
  template<class Predicate>
  inline iterator
  longest_prefix_match_if (const FullKey &key, Predicate pred)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find_if (key, pred);
    if (foundItem != trie_.end ())
      {
        policy_.lookup (s_iterator_to (foundItem));
      }
    return foundItem;
  }

  // /**
  //  * @brief Const version of the longest common prefix match
  //  * (semi-const, because there could be update of the policy anyways)
  //  */
  // inline const_iterator
  // longest_prefix_match (const FullKey &key) const
  // {
  //   return static_cast<trie_with_policy*> (this)->longest_prefix_match (key);
  // }

  /**
   * @brief Find a node that has prefix at least as the key (cache lookup)
   */
  inline iterator
  deepest_prefix_match (const FullKey &key)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);

    // guard in case we don't have anything in the trie
    if (lastItem == trie_.end ())
      return trie_.end ();

    if (reachLast)
      {
        if (foundItem == trie_.end ())
          {
            foundItem = lastItem->find (); // should be something
          }
        policy_.lookup (s_iterator_to (foundItem));
        return foundItem;
      }
    else
      { // couldn't find a node that has prefix at least as key
        return trie_.end ();
      }
  }

  /**
   * @brief Find a node that has prefix at least as the key
   */
  template<class Predicate>
  inline iterator
  deepest_prefix_match_if (const FullKey &key, Predicate pred)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);

    // guard in case we don't have anything in the trie
    if (lastItem == trie_.end ())
      return trie_.end ();

    if (reachLast)
      {
        foundItem = lastItem->find_if (pred); // may or may not find something
        if (foundItem == trie_.end ())
          {
            return trie_.end ();
          }
        policy_.lookup (s_iterator_to (foundItem));
        return foundItem;
      }
    else
      { // couldn't find a node that has prefix at least as key
        return trie_.end ();
      }
  }

  /**
   * @brief Find a node that has prefix at least as the key
   *
   * This version of find checks predicate for the next level and if
   * predicate is True, returns first deepest match available
   */
  template<class Predicate>
  inline iterator
  deepest_prefix_match_if_next_level (const FullKey &key, Predicate pred)
  {
    iterator foundItem, lastItem;
    bool reachLast;
    boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);

    // guard in case we don't have anything in the trie
    if (lastItem == trie_.end ())
      return trie_.end ();

    if (reachLast)
      {
        foundItem = lastItem->find_if_next_level (pred); // may or may not find something
        if (foundItem == trie_.end ())
          {
            return trie_.end ();
          }
        policy_.lookup (s_iterator_to (foundItem));
        return foundItem;
      }
    else
      { // couldn't find a node that has prefix at least as key
        return trie_.end ();
      }
  }
  
  iterator end () const
  {
    return 0;
  }

  const parent_trie &
  getTrie () const { return trie_; }

  parent_trie &
  getTrie () { return trie_; }

  const policy_container &
  getPolicy () const { return policy_; }

  policy_container &
  getPolicy () { return policy_; }

  static inline iterator
  s_iterator_to (typename parent_trie::iterator item)
  {
    if (item == 0)
      return 0;
    else
      return &(*item);
  }

private:
  parent_trie      trie_;
  mutable policy_container policy_;
};

} // ndnSIM
} // ndn
} // ns3

#endif // TRIE_WITH_POLICY_H_
