//===========================================================================
//  $Name: arts++-1-1-a12 $
//  $Id: ArtsBgp4RouteEntry.cc,v 1.2 2004/04/21 23:51:31 kkeys Exp $
//===========================================================================
//  Copyright Notice
//
//  By accessing this software, arts++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, arts++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for arts++ software.  You can redistribute it
//  and/or modify it under the terms of the GNU Lesser General Public
//  License, Version 2.1, February 1999, which is incorporated by
//  reference herein.
//
//  arts++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual
//  property rights.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with arts++.  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/lesser.html
//
//  or by writing to:
//
//  Free Software Foundation, Inc.
//  59 Temple Place, Suite 330
//  Boston, MA 02111-1307
//  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

#include <string>
#include "ArtsPrimitive.hh"
#include "ArtsBgp4RouteEntry.hh"

using namespace std;

static const std::string rcsid = "@(#) $Name: arts++-1-1-a12 $ $Id: ArtsBgp4RouteEntry.cc,v 1.2 2004/04/21 23:51:31 kkeys Exp $";

//----------------------------------------------------------------------------
//                 ArtsBgp4RouteEntry::ArtsBgp4RouteEntry()                
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsBgp4RouteEntry::ArtsBgp4RouteEntry()
{
  this->_attrIndex = 0;
  
  #ifndef NDEBUG
    ++_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//               ArtsBgp4RouteEntry::ArtsBgp4RouteEntry(int)               
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsBgp4RouteEntry::ArtsBgp4RouteEntry(int)
{
  this->_attrIndex = 0;
  #ifndef NDEBUG
    ++_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//                ArtsBgp4RouteEntry::~ArtsBgp4RouteEntry()                
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsBgp4RouteEntry::~ArtsBgp4RouteEntry()
{
  if (! (*this)._attributes.empty())
    (*this)._attributes.erase((*this)._attributes.begin(),
                              (*this)._attributes.end());
  
  #ifndef NDEBUG
    --_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//                     const ArtsBgp4AsPathAttribute *                     
//                     ArtsBgp4RouteEntry::AsPathAttribute() const         
//............................................................................
//  
//----------------------------------------------------------------------------
const ArtsBgp4AsPathAttribute *
ArtsBgp4RouteEntry::AsPathAttribute() const
{
  vector<ArtsBgp4Attribute>::const_iterator  bgp4AttrIter;
  for (bgp4AttrIter = this->_attributes.begin();
       bgp4AttrIter != this->_attributes.end(); bgp4AttrIter++) {
    if ((*bgp4AttrIter).Type() == Bgp4_Attribute_AsPath)
      return((*bgp4AttrIter).AsPath());
  }
  return((ArtsBgp4AsPathAttribute *)0);
}

//----------------------------------------------------------------------------
//           uint32_t ArtsBgp4RouteEntry::AttributeIndex() const           
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsBgp4RouteEntry::AttributeIndex() const
{
  return(this->_attrIndex);
}

//----------------------------------------------------------------------------
//  istream & ArtsBgp4RouteEntry::read(istream & is, uint8_t version)  
//............................................................................
//  
//----------------------------------------------------------------------------
istream & ArtsBgp4RouteEntry::read(istream & is, uint8_t version)
{
  ArtsBgp4Attribute  bgp4Attribute;

  if (! (*this)._attributes.empty())
    (*this)._attributes.erase((*this)._attributes.begin(),
                              (*this)._attributes.end());
  
  g_ArtsLibInternal_Primitive.ReadUint32(is,this->_attrIndex,
                                         sizeof(this->_attrIndex));
  
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Origin)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_AsPath)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_NextHop)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MultiExitDisc)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_LocalPref)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_AtomicAggregate)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Aggregator)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Community)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_DPA)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MPReachNLRI)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MPUnreachNLRI)) {
    bgp4Attribute.read(is,version);
    this->_attributes.push_back(bgp4Attribute);
  }

  return(is);
}

//----------------------------------------------------------------------------
//        int ArtsBgp4RouteEntry::read(int fd, uint8_t version)        
//............................................................................
//  
//----------------------------------------------------------------------------
int ArtsBgp4RouteEntry::read(int fd, uint8_t version)
{
  int                rc;
  ArtsBgp4Attribute  bgp4Attribute;
  int                bytesRead = 0;

  rc = g_ArtsLibInternal_Primitive.ReadUint32(fd,this->_attrIndex,
                                              sizeof(this->_attrIndex));
  if (rc < sizeof(this->_attrIndex))
    return(-1);
  bytesRead += rc;

  if (! (*this)._attributes.empty())
    (*this)._attributes.erase((*this)._attributes.begin(),
                              (*this)._attributes.end());
  
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Origin)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_AsPath)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_NextHop)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MultiExitDisc)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_LocalPref)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;    
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_AtomicAggregate)) {
    rc = bgp4Attribute.read(fd,version);
        if (rc < 0)
      return(-1);
    bytesRead += rc;

    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Aggregator)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_Community)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_DPA)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MPReachNLRI)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  if (this->_attrIndex & ((uint32_t)1 << Bgp4_Attribute_MPUnreachNLRI)) {
    rc = bgp4Attribute.read(fd,version);
    if (rc < 0)
      return(-1);
    bytesRead += rc;
    this->_attributes.push_back(bgp4Attribute);
  }
  return(bytesRead);
}

//----------------------------------------------------------------------------
//      ostream & ArtsBgp4RouteEntry::write(ostream& os,
//                                          uint8_t version) const
//............................................................................
//  
//----------------------------------------------------------------------------
ostream & ArtsBgp4RouteEntry::write(ostream & os, uint8_t version) const
{
  g_ArtsLibInternal_Primitive.WriteUint32(os,this->_attrIndex,
                                          sizeof(this->_attrIndex));
  vector<ArtsBgp4Attribute>::const_iterator  bgp4AttrIter;

  for (bgp4AttrIter = this->_attributes.begin();
       bgp4AttrIter != this->_attributes.end(); bgp4AttrIter++) {
    (*bgp4AttrIter).write(os,version);
  }
  return(os);
}

//----------------------------------------------------------------------------
//     int ArtsBgp4RouteEntry::write(int fd, uint8_t version) const    
//............................................................................
//  
//----------------------------------------------------------------------------
int ArtsBgp4RouteEntry::write(int fd, uint8_t version) const
{
  int   rc;
  int   bytesWritten = 0;
  
  rc = g_ArtsLibInternal_Primitive.WriteUint32(fd,this->_attrIndex,
                                               sizeof(this->_attrIndex));
  if (rc < sizeof(this->_attrIndex))
    return(-1);
  bytesWritten += rc;
  
  vector<ArtsBgp4Attribute>::const_iterator  bgp4AttrIter;

  for (bgp4AttrIter = this->_attributes.begin();
       bgp4AttrIter != this->_attributes.end(); bgp4AttrIter++) {
    rc = (*bgp4AttrIter).write(fd,version);
    if (rc < 0)
      return(-1);
    bytesWritten += rc;
  }
  return(bytesWritten);
}

//----------------------------------------------------------------------------
//      uint32_t ArtsBgp4RouteEntry::Length(uint8_t version) const     
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsBgp4RouteEntry::Length(uint8_t version) const
{
  uint32_t  length = sizeof(this->_attrIndex);
  vector<ArtsBgp4Attribute>::const_iterator  bgp4AttrIter;
  
  for (bgp4AttrIter = this->_attributes.begin();
       bgp4AttrIter != this->_attributes.end(); bgp4AttrIter++) {
    length += bgp4AttrIter->Length(version);
  }
  return(length);
}

//----------------------------------------------------------------------------
//  bool                                  
//  ArtsBgp4RouteEntry::AddBgp4Attribute(const ArtsBgp4Attribute & bgp4Attr) 
//............................................................................
//  
//----------------------------------------------------------------------------
bool
ArtsBgp4RouteEntry::AddBgp4Attribute(const ArtsBgp4Attribute & bgp4Attr)
{
  if (this->_attrIndex & ((uint32_t)1 << bgp4Attr.Type())) {
    //  we already have this type of attribute.
    return(false);
  }
  this->_attributes.push_back(bgp4Attr);
  this->_attrIndex |= ((uint32_t)1 << bgp4Attr.Type());
  
  return(true);
}

//----------------------------------------------------------------------------
//              void ArtsBgp4RouteEntry::ClearBgpAttributes()              
//............................................................................
//  
//----------------------------------------------------------------------------
void ArtsBgp4RouteEntry::ClearBgpAttributes()
{
  if (! (*this)._attributes.empty()) {
    (*this)._attributes.erase((*this)._attributes.begin(),
                              (*this)._attributes.end());
  }
  
  this->_attrIndex = 0;
  return;
}

//----------------------------------------------------------------------------
// ArtsBgp4RouteEntry &                          
// ArtsBgp4RouteEntry::operator = (const ArtsBgp4RouteEntry & bgp4RouteEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsBgp4RouteEntry &
ArtsBgp4RouteEntry::operator = (const ArtsBgp4RouteEntry & bgp4RouteEntry)
{
  this->_attrIndex = bgp4RouteEntry.AttributeIndex();
  //  this->_attributes.reserve(bgp4RouteEntry.BgpAttributes().size());
  this->_attributes = bgp4RouteEntry.BgpAttributes();
  return(*this);
}

//----------------------------------------------------------------------------
//      ostream& operator << (ostream & os,                   
//                            const ArtsBgp4RouteEntry & bgp4RouteEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ostream & operator << (ostream & os,
                       const ArtsBgp4RouteEntry & bgp4RouteEntry)
{
  os << "\t\tattribute index: 0x" << hex << bgp4RouteEntry.AttributeIndex()
     << dec << endl;
  os << "\t\tnum attributes: " << bgp4RouteEntry.BgpAttributes().size()
     << endl;
   
  vector<ArtsBgp4Attribute>::iterator  bgpAttrIter;
  for (bgpAttrIter = bgp4RouteEntry.BgpAttributes().begin();
       bgpAttrIter != bgp4RouteEntry.BgpAttributes().end(); bgpAttrIter++) {
    os << (*bgpAttrIter);
  }
  return(os);
}


uint32_t  ArtsBgp4RouteEntry::_numObjects = 0;
