//===========================================================================
//  @(#) $Name: arts++-1-1-a12 $
//  @(#) $Id: ArtsProtocolTableEntry.cc,v 1.3 2004/10/22 18:26:27 rkoga 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
//===========================================================================

extern "C" {
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
}

#include <string>

#include "ArtsPrimitive.hh"
#include "ArtsProtocolTableEntry.hh"

using namespace std;

static const std::string rcsid = "@(#) $Name: arts++-1-1-a12 $ $Id: ArtsProtocolTableEntry.cc,v 1.3 2004/10/22 18:26:27 rkoga Exp $";

//-------------------------------------------------------------------------
//             ArtsProtocolTableEntry::ArtsProtocolTableEntry()
//-------------------------------------------------------------------------
ArtsProtocolTableEntry::ArtsProtocolTableEntry()
{
  this->_descriptor = 0;
  this->_protocolNum = 0;
  this->_pkts = 0;
  this->_bytes = 0;

  #ifndef NDEBUG
    ++ArtsProtocolTableEntry::_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//     ArtsProtocolTableEntry:: 
//     ArtsProtocolTableEntry(const ArtsProtocolTableEntry & protoEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsProtocolTableEntry::
ArtsProtocolTableEntry(const ArtsProtocolTableEntry & protoEntry)
{
  this->_protocolNum = protoEntry._protocolNum;
  this->_descriptor = protoEntry._descriptor;
  this->_pkts = protoEntry._pkts;
  this->_bytes = protoEntry._bytes;

  #ifndef NDEBUG
    ++ArtsProtocolTableEntry::_numObjects;
  #endif
}

//-------------------------------------------------------------------------
//            ArtsProtocolTableEntry::~ArtsProtocolTableEntry()
//-------------------------------------------------------------------------
ArtsProtocolTableEntry::~ArtsProtocolTableEntry()
{
  #ifndef NDEBUG
    --ArtsProtocolTableEntry::_numObjects;
  #endif
}

//-------------------------------------------------------------------------
//         uint8_t ArtsProtocolTableEntry::ProtocolNumber() const
//-------------------------------------------------------------------------
uint8_t ArtsProtocolTableEntry::ProtocolNumber() const
{
  return(this->_protocolNum);
}

//-------------------------------------------------------------------------
//  uint8_t ArtsProtocolTableEntry::ProtocolNumber(uint8_t protocolNum)
//-------------------------------------------------------------------------
uint8_t ArtsProtocolTableEntry::ProtocolNumber(uint8_t protocolNum)
{
  this->_protocolNum = protocolNum;
  return(this->_protocolNum);
}

//-------------------------------------------------------------------------
//             uint64_t ArtsProtocolTableEntry::Pkts() const
//-------------------------------------------------------------------------
uint64_t ArtsProtocolTableEntry::Pkts() const
{
  return(this->_pkts);
}

//-------------------------------------------------------------------------
//          uint64_t ArtsProtocolTableEntry::Pkts(uint64_t pkts)
//-------------------------------------------------------------------------
uint64_t ArtsProtocolTableEntry::Pkts(uint64_t pkts)
{
  this->_pkts = pkts;

  if (pkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xc7) | 0x38;    // use 8 bytes
  } else if (pkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xc7) | 0x18;    // use 4 bytes
  } else if (pkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xc7) | 0x08;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xc7);           // use 1 byte
  }
  return(this->_pkts);
}

//-------------------------------------------------------------------------
//            uint64_t ArtsProtocolTableEntry::Bytes() const
//-------------------------------------------------------------------------
uint64_t ArtsProtocolTableEntry::Bytes() const
{
  return(this->_bytes);
}

//-------------------------------------------------------------------------
//        uint64_t ArtsProtocolTableEntry::Bytes(uint64_t bytes)
//-------------------------------------------------------------------------
uint64_t ArtsProtocolTableEntry::Bytes(uint64_t bytes)
{
  this->_bytes = bytes;

  if (bytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xf8) | 0x07;    // use 8 bytes
  } else if (bytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xf8) | 0x03;    // use 4 bytes
  } else if (bytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xf8) | 0x01;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xf8);           // use 1 byte
  }
  
  return(this->_bytes);
}

//-------------------------------------------------------------------------
//          uint8_t ArtsProtocolTableEntry::Descriptor() const
//-------------------------------------------------------------------------
uint8_t ArtsProtocolTableEntry::Descriptor() const
{
  return(this->_descriptor);
}

//-------------------------------------------------------------------------
//    uint8_t ArtsProtocolTableEntry::Descriptor(uint8_t descriptor)
//-------------------------------------------------------------------------
uint8_t ArtsProtocolTableEntry::Descriptor(uint8_t descriptor)
{
  this->_descriptor = descriptor;
  return(this->_descriptor);
}

//-------------------------------------------------------------------------
//   uint32_t ArtsProtocolTableEntry::Length(uint8_t version) const
//-------------------------------------------------------------------------
uint32_t ArtsProtocolTableEntry::Length(uint8_t version) const
{
  uint32_t  len = 0;

  len += sizeof(this->_protocolNum);
  len += sizeof(this->_descriptor);
  len += (((this->_descriptor >> 3) + 1) +
          ((this->_descriptor & 0x07) + 1));
  
  return(len);
}

//-------------------------------------------------------------------------
// istream& ArtsProtocolTableEntry::read(istream& is, uint8_t version)
//-------------------------------------------------------------------------
istream& ArtsProtocolTableEntry::read(istream& is, uint8_t version)
{
  uint8_t  fieldLen;

  //  protocol number
  is.read((char*)&this->_protocolNum,sizeof(this->_protocolNum));
  
  //  descriptor
  is.read((char*)&this->_descriptor,sizeof(this->_descriptor));

  //  pkts
  fieldLen = (this->_descriptor >> 3) + 1;
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_pkts,fieldLen);

  //  bytes
  fieldLen = (this->_descriptor & 0x07) + 1;
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_bytes,fieldLen);

  return(is);
}

//-------------------------------------------------------------------------
//      int ArtsProtocolTableEntry::read(int fd, uint8_t version)
//-------------------------------------------------------------------------
int ArtsProtocolTableEntry::read(int fd, uint8_t version)
{
  uint8_t  fieldLen;
  int      rc = 0;

  //  protocol number
  rc += g_ArtsLibInternal_Primitive.FdRead(fd,&this->_protocolNum,
                                           sizeof(this->_protocolNum));
  
  //  descriptor
  rc += g_ArtsLibInternal_Primitive.FdRead(fd,&this->_descriptor,1);
  
  //  pkts
  fieldLen = (this->_descriptor >> 3) + 1;
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_pkts,fieldLen);

  //  bytes
  fieldLen = (this->_descriptor & 0x07) + 1;
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_bytes,fieldLen);

  if (rc != (int)this->Length(version))
    rc = -1;

  return(rc);
}

//-------------------------------------------------------------------------
//    ostream& ArtsProtocolTableEntry::write(ostream& os,
//                                           uint8_t version) const
//-------------------------------------------------------------------------
ostream& ArtsProtocolTableEntry::write(ostream& os,
                                       uint8_t version) const
{
  uint8_t  fieldLen;

  //  protocol number
  os.write((char*)&this->_protocolNum,sizeof(this->_protocolNum));
  
  //  descriptor
  os.write((char*)&this->_descriptor,1);
  
  //  pkts
  fieldLen = (this->_descriptor >> 3) + 1;
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_pkts,fieldLen);

  //  bytes
  fieldLen = (this->_descriptor & 0x07) + 1;
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_bytes,fieldLen);

  return(os);
}

//-------------------------------------------------------------------------
//  int ArtsProtocolTableEntry::write(int fd, uint8_t version) const
//-------------------------------------------------------------------------
int ArtsProtocolTableEntry::write(int fd, uint8_t version) const
{
  uint8_t  fieldLen;
  int      rc = 0;

  //  protocol number
  rc += g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_protocolNum,
                                            sizeof(this->_protocolNum));

  //  descriptor
  rc += g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_descriptor,1);

  //  pkts
  fieldLen = (this->_descriptor >> 3) + 1;
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_pkts,fieldLen);

  //  bytes
  fieldLen = (this->_descriptor & 0x07) + 1;
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_bytes,fieldLen);

  if (rc != (int)this->Length(version))
    rc = -1;

  return(rc);
}

//-------------------------------------------------------------------------
//   ArtsProtocolTableEntry &
//   operator = (const ArtsProtocolTableEntry & artsProtocolTableEntry)
//-------------------------------------------------------------------------
ArtsProtocolTableEntry &
ArtsProtocolTableEntry::operator = (const ArtsProtocolTableEntry & artsProtocolTableEntry)
{
  this->_protocolNum = artsProtocolTableEntry._protocolNum;
  this->_descriptor = artsProtocolTableEntry._descriptor;
  this->_pkts = artsProtocolTableEntry._pkts;
  this->_bytes = artsProtocolTableEntry._bytes;
  return(*this);
}

//-------------------------------------------------------------------------
//   ostream &                                
//   operator << (ostream& os,                
//                const ArtsProtocolTableEntry & artsProtocolTableEntry) 
//-------------------------------------------------------------------------
ostream &
operator << (ostream& os,
             const ArtsProtocolTableEntry & artsProtocolTableEntry)
{
  os << "\tPROTOCOL TABLE ENTRY" << endl;
  os << "\t\tprotocol: " << (int)artsProtocolTableEntry.ProtocolNumber()
     << endl;
  os << "\t\tdescriptor: 0x"
     << hex << (int)artsProtocolTableEntry.Descriptor() << dec << endl;
  os << "\t\tpkts: " << artsProtocolTableEntry.Pkts() << endl;
  os << "\t\tbytes: " << artsProtocolTableEntry.Bytes() << endl;
  return(os);
}

//---------------------------------------------------------------------------
//      bool ArtsProtocolEntryGreaterBytes::
//      operator()(const ArtsProtocolTableEntry & protoEntry1,
//                 const ArtsProtocolTableEntry & protoEntry2) const
//---------------------------------------------------------------------------
bool ArtsProtocolEntryGreaterBytes::
operator()(const ArtsProtocolTableEntry & protoEntry1,
           const ArtsProtocolTableEntry & protoEntry2) const
{
  return(protoEntry1.Bytes() > protoEntry2.Bytes());
}

//---------------------------------------------------------------------------
//        bool ArtsProtocolEntryGreaterPkts::
//        operator()(const ArtsProtocolTableEntry & protoEntry1,
//                   const ArtsProtocolTableEntry & protoEntry2) const
//---------------------------------------------------------------------------
bool ArtsProtocolEntryGreaterPkts::
operator()(const ArtsProtocolTableEntry & protoEntry1,
           const ArtsProtocolTableEntry & protoEntry2) const
{
  return(protoEntry1.Pkts() > protoEntry2.Pkts());
}

uint32_t ArtsProtocolTableEntry::_numObjects = 0;
