//===========================================================================
//  We need a means of storing data keyed by any combination of fields
//  from a flow.  This isn't pretty... the idea here is to use a
//  memory-efficient mechanism, so we use an array of bytes to hold key
//  values in a packed form.  It's harder code to maintain and more
//  CPU-intensive than some other possible implementations (especially
//  since we can't prevent non-aligned access and hence wind up using
//  memcmp() and the like), but it's reasonably memory efficient.  Note
//  we waste 4 bytes per key to keep an index, which also indicates the
//  key length (which is computed from the index when needed).
//===========================================================================

#ifndef _ARTSCFLOWDCUSTOMDATA_HH_
#define _ARTSCFLOWDCUSTOMDATA_HH_

extern "C" {
#include <string.h>
  
#include "caida_t.h"
}

#include <map>

//----------------------------------------------------------------------------
//                      class ArtsCflowdCustomDataKey 
//----------------------------------------------------------------------------
//  We need a means of storing data keyed by any combination of fields
//  from a flow.  This isn't pretty... the idea here is to use a
//  memory-efficient mechanism, so we use an array of bytes to hold key
//  values in a packed form.  It's harder code to maintain and more
//  CPU-intensive than some other possible implementations (especially
//  since we can't prevent non-aligned access and hence wind up using
//  memcmp() and the like), but it's reasonably memory efficient.  Note
//  we waste 4 bytes per key to keep an index, which also indicates the
//  key length (which is computed from the index when needed).
//----------------------------------------------------------------------------
class ArtsCflowdCustomDataKey
{
public:
  typedef uint32_t  index_type;
  
  static const index_type k_routerBit        = 0;
  static const index_type k_srcIpAddrBit     = 1;
  static const index_type k_dstIpAddrBit     = 2;
  static const index_type k_inputIfIndexBit  = 3;
  static const index_type k_outputIfIndexBit = 4;
  static const index_type k_srcPortBit       = 5;
  static const index_type k_dstPortBit       = 6;
  static const index_type k_ipNextHopBit     = 7;
  static const index_type k_protocolBit      = 8;
  static const index_type k_tosBit           = 9;
  static const index_type k_srcAsBit         = 10;
  static const index_type k_dstAsBit         = 11;
  static const index_type k_srcMaskLenBit    = 12;
  static const index_type k_dstMaskLenBit    = 13;
  static const index_type k_tcpFlagsBit      = 14;
  static const index_type k_engineTypeBit    = 15;
  static const index_type k_engineIdBit      = 16;

  static const index_type k_maxBit           = k_engineIdBit;

  static const uint8_t k_fieldSizes[k_maxBit + 1];

  //-------------------------------------------------------------------------
  //                 ArtsCflowdCustomDataKey(uint32_t index)
  //.........................................................................
  //  
  //-------------------------------------------------------------------------
  ArtsCflowdCustomDataKey(uint32_t index);

  //--------------------------------------------------------------------------
  //      ArtsCflowdCustomDataKey(const ArtsCflowdCustomDataKey & key) 
  //..........................................................................
  //  copy constructor
  //--------------------------------------------------------------------------
  ArtsCflowdCustomDataKey(const ArtsCflowdCustomDataKey & key);
  
  //--------------------------------------------------------------------------
  //                 inline ~ArtsCflowdCustomDataKey() 
  //..........................................................................
  //  destructor
  //--------------------------------------------------------------------------
  inline ~ArtsCflowdCustomDataKey()
  {
    if (this->_index) {
      if (this->_value) {
        free(this->_value);
      }
    }
  }
  
  //-------------------------------------------------------------------------
  //                        uint8_t KeyLength() const       
  //.........................................................................
  //  Returns the length (in bytes) of the key data (excluding the index).
  //-------------------------------------------------------------------------
  uint8_t KeyLength() const;

  //--------------------------------------------------------------------------
  //                      inline uint32_t Index() const 
  //..........................................................................
  //  Returns the index for the key.
  //--------------------------------------------------------------------------
  inline uint32_t Index() const
  {
    return(this->_index);
  }

  //--------------------------------------------------------------------------
  //                       uint8_t IndexLength() const 
  //..........................................................................
  //  Returns the number of bits used in the index.
  //--------------------------------------------------------------------------
  uint8_t IndexLength() const;

  //-------------------------------------------------------------------------
  //       bool operator < (const ArtsCflowdCustomDataKey & key) const
  //.........................................................................
  //  
  //-------------------------------------------------------------------------
  bool operator < (const ArtsCflowdCustomDataKey & key) const;

protected:
  caddr_t  _value;
  
private:
  uint32_t  _index;

  //--------------------------------------------------------------------------
  //              uint32_t FieldOffset(uint32_t fieldBit) const 
  //..........................................................................
  //  Returns the offset (in bytes) of a field from _value.
  //--------------------------------------------------------------------------
  uint32_t FieldOffset(uint32_t fieldBit) const;
  
};

class ArtsCflowdCustomData :
  public std::map<ArtsCflowdCustomDataKey,uint64_t[2],std::less<ArtsCflowdCustomDataKey> >
{
public:
  ArtsCflowdCustomDataKey::index_type Index() const;
  ArtsCflowdCustomDataKey::index_type
  Index(ArtsCflowdCustomDataKey::index_type index);
};


#endif  // _ARTSCFLOWDCUSTOMDATA_HH_
