//===========================================================================
//  @(#) $Name: arts++-1-1-a12 $
//  @(#) $Id: ArtsPortTableEntry.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 "ArtsPortTableEntry.hh"

using namespace std;

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

//-------------------------------------------------------------------------
//                 ArtsPortTableEntry::ArtsPortTableEntry()                
//-------------------------------------------------------------------------
ArtsPortTableEntry::ArtsPortTableEntry()
{
  this->_descriptor = 0;
  this->_portNum = 0;
  this->_inPkts = 0;
  this->_inBytes = 0;
  this->_outPkts = 0;
  this->_outBytes = 0;

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

//----------------------------------------------------------------------------
//        ArtsPortTableEntry:: 
//        ArtsPortTableEntry(const ArtsPortTableEntry & portEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsPortTableEntry::
ArtsPortTableEntry(const ArtsPortTableEntry & portEntry)
{
  this->_descriptor = portEntry.Descriptor();
  this->_portNum = portEntry.PortNumber();
  this->_inPkts = portEntry.InPkts();
  this->_inBytes = portEntry.InBytes();
  this->_outPkts = portEntry.OutPkts();
  this->_outBytes = portEntry.OutBytes();

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

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

//-------------------------------------------------------------------------
//            uint16_t ArtsPortTableEntry::PortNumber() const
//-------------------------------------------------------------------------
uint16_t ArtsPortTableEntry::PortNumber() const
{
  return(this->_portNum);
}

//-------------------------------------------------------------------------
//        uint16_t ArtsPortTableEntry::PortNumber(uint16_t portNum)
//-------------------------------------------------------------------------
uint16_t ArtsPortTableEntry::PortNumber(uint16_t portNum)
{
  this->_portNum = portNum;
  return(this->_portNum);
}

//-------------------------------------------------------------------------
//                uint64_t ArtsPortTableEntry::InPkts() const                
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::InPkts() const
{
  return(this->_inPkts);
}

//-------------------------------------------------------------------------
//             uint64_t ArtsPortTableEntry::InPkts(uint64_t pkts)            
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::InPkts(uint64_t pkts)
{
  this->_inPkts = pkts;

  if (pkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0xc0;    // use 8 bytes
  } else if (pkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0x80;    // use 4 bytes
  } else if (pkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0x40;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0x3f);           // use 1 byte
  }
  return(this->_inPkts);
}

//----------------------------------------------------------------------------
//     uint64_t ArtsPortTableEntry::AddInPkts(uint64_t pkts) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::AddInPkts(uint64_t pkts)
{
  this->_inPkts += pkts;

  if (this->_inPkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0xc0;    // use 8 bytes
  } else if (this->_inPkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0x80;    // use 4 bytes
  } else if (this->_inPkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0x3f) | 0x40;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0x3f);           // use 1 byte
  }
  return(this->_inPkts);
}

//-------------------------------------------------------------------------
//                uint64_t ArtsPortTableEntry::InBytes() const               
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::InBytes() const
{
  return(this->_inBytes);
}

//-------------------------------------------------------------------------
//            uint64_t ArtsPortTableEntry::InBytes(uint64_t bytes)           
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::InBytes(uint64_t bytes)
{
  this->_inBytes = bytes;

  if (bytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x30;    // use 8 bytes
  } else if (bytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x20;    // use 4 bytes
  } else if (bytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x10;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xcf);           // use 1 byte
  }
  
  return(this->_inBytes);
}

//----------------------------------------------------------------------------
//     uint64_t ArtsPortTableEntry::AddInBytes(uint64_t bytes) 
//----------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::AddInBytes(uint64_t bytes)
{
  this->_inBytes += bytes;

  if (this->_inBytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x30;    // use 8 bytes
  } else if (this->_inBytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x20;    // use 4 bytes
  } else if (this->_inBytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xcf) | 0x10;    // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xcf);           // use 1 byte
  }
  
  return(this->_inBytes);
}

//-------------------------------------------------------------------------
//                uint64_t ArtsPortTableEntry::OutPkts() const                
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::OutPkts() const
{
  return(this->_outPkts);
}

//-------------------------------------------------------------------------
//             uint64_t ArtsPortTableEntry::OutPkts(uint64_t pkts)            
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::OutPkts(uint64_t pkts)
{
  this->_outPkts = pkts;

  if (pkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x0c;   // use 8 bytes
  } else if (pkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x08;   // use 4 bytes
  } else if (pkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x04;   // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xf3);          // use 1 byte
  }
  
  return(this->_outPkts);
}

//----------------------------------------------------------------------------
//     uint64_t ArtsPortTableEntry::AddOutPkts(uint64_t pkts) 
//----------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::AddOutPkts(uint64_t pkts)
{
  this->_outPkts += pkts;

  if (this->_outPkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x0c;   // use 8 bytes
  } else if (this->_outPkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x08;   // use 4 bytes
  } else if (this->_outPkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xf3) | 0x04;   // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xf3);          // use 1 byte
  }
  
  return(this->_outPkts);
}

//-------------------------------------------------------------------------
//                uint64_t ArtsPortTableEntry::OutBytes() const               
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::OutBytes() const
{
  return(this->_outBytes);
}

//-------------------------------------------------------------------------
//            uint64_t ArtsPortTableEntry::OutBytes(uint64_t bytes)           
//-------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::OutBytes(uint64_t bytes)
{
  this->_outBytes = bytes;
  
  if (bytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x03;   // use 8 bytes
  } else if (bytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x02;   // use 4 bytes
  } else if (bytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x01;   // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xfc);          // use 1 byte
  }

  return(this->_outBytes);
}

//----------------------------------------------------------------------------
//     uint64_t ArtsPortTableEntry::AddOutBytes(uint64_t bytes) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint64_t ArtsPortTableEntry::AddOutBytes(uint64_t bytes)
{
  this->_outBytes += bytes;
  
  if (this->_outBytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x03;   // use 8 bytes
  } else if (this->_outBytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x02;   // use 4 bytes
  } else if (this->_outBytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xfc) | 0x01;   // use 2 bytes
  } else {
    this->_descriptor = (this->_descriptor & 0xfc);          // use 1 byte
  }

  return(this->_outBytes);
}

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

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

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

  len += sizeof(this->_portNum);
  len += sizeof(this->_descriptor);
  len += ((1 << (this->_descriptor >> 6)) +
          (1 << ((this->_descriptor >> 4) & 0x03)) +
          (1 << ((this->_descriptor >> 2) & 0x03)) +
          (1 << (this->_descriptor & 0x03)));
  
  return(len);
}

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

  //  port number
  g_ArtsLibInternal_Primitive.ReadUint16(is,this->_portNum,
                                         sizeof(this->_portNum));
  
  //  descriptor
  is.read((char*)&this->_descriptor,sizeof(this->_descriptor));

  //  inPkts
  fieldLen = 1 << (this->_descriptor >> 6);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_inPkts,fieldLen);

  //  inBytes
  fieldLen = 1 << ((this->_descriptor >> 4) & 0x03);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_inBytes,fieldLen);

  //  outPkts
  fieldLen = 1 << ((this->_descriptor >> 2) & 0x03);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_outPkts,fieldLen);

  //  outBytes
  fieldLen = 1 << (this->_descriptor & 0x03);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_outBytes,fieldLen);

  return(is);
}

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

  //  port number
  rc += g_ArtsLibInternal_Primitive.ReadUint16(fd,this->_portNum,
                                               sizeof(this->_portNum));
  
  //  descriptor
  rc += g_ArtsLibInternal_Primitive.FdRead(fd,&this->_descriptor,1);
  
  //  inPkts
  fieldLen = 1 << (this->_descriptor >> 6);
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_inPkts,fieldLen);

  //  inBytes
  fieldLen = 1 << ((this->_descriptor >> 4) & 0x03);
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_inBytes,fieldLen);

  //  outPkts
  fieldLen = 1 << ((this->_descriptor >> 2) & 0x03);
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_outPkts,fieldLen);

  //  outBytes
  fieldLen = 1 << (this->_descriptor & 0x03);
  rc += g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_outBytes,fieldLen);

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

  return(rc);
}

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

  //  port number
  g_ArtsLibInternal_Primitive.WriteUint16(os,this->_portNum,
                                          sizeof(this->_portNum));
  
  //  descriptor
  os.write((char*)&this->_descriptor,1);
  
  //  inPkts
  fieldLen = 1 << (this->_descriptor >> 6);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_inPkts,fieldLen);

  //  inBytes
  fieldLen = 1 << ((this->_descriptor >> 4) & 0x03);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_inBytes,fieldLen);
  
  //  outPkts
  fieldLen = 1 << ((this->_descriptor >> 2) & 0x03);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_outPkts,fieldLen);

  //  outBytes
  fieldLen = 1 << (this->_descriptor & 0x03);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_outBytes,fieldLen);

  return(os);
}

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

  //  port number
  rc += g_ArtsLibInternal_Primitive.WriteUint16(fd,this->_portNum,
                                                sizeof(this->_portNum));

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

  //  inPkts
  fieldLen = 1 << (this->_descriptor >> 6);
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_inPkts,fieldLen);

  //  inBytes
  fieldLen = 1 << ((this->_descriptor >> 4) & 0x03);
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_inBytes,fieldLen);

  //  outPkts
  fieldLen = 1 << ((this->_descriptor >> 2) & 0x03);
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_outPkts,fieldLen);

  //  outBytes
  fieldLen = 1 << (this->_descriptor & 0x03);
  rc += g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_outBytes,fieldLen);

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

  return(rc);
}

//-------------------------------------------------------------------------
//      ArtsPortTableEntry &
//      operator = (const ArtsPortTableEntry & artsPortTableEntry)
//-------------------------------------------------------------------------
ArtsPortTableEntry &
ArtsPortTableEntry::operator = (const ArtsPortTableEntry & artsPortTableEntry)
{
  this->_portNum = artsPortTableEntry.PortNumber();
  this->_descriptor = artsPortTableEntry.Descriptor();
  this->_inPkts = artsPortTableEntry.InPkts();
  this->_inBytes = artsPortTableEntry.InBytes();
  this->_outPkts = artsPortTableEntry.OutPkts();
  this->_outBytes = artsPortTableEntry.OutBytes();
  return(*this);
}

//-------------------------------------------------------------------------
//   ostream & operator << (ostream& os,                   
//                          const ArtsPortTableEntry & artsPortTableEntry) 
//.........................................................................
//  
//-------------------------------------------------------------------------
ostream & operator << (ostream& os,
                       const ArtsPortTableEntry & artsPortTableEntry)
{
  os << "\tPORT TABLE ENTRY" << endl;
  os << "\t\tport: " << artsPortTableEntry.PortNumber() << endl;
  os << "\t\tdescriptor: " << "0x"
     << hex << (int)artsPortTableEntry.Descriptor() << dec << endl;
  os << "\t\tinpkts: " << artsPortTableEntry.InPkts() << endl;
  os << "\t\tinbytes: " << artsPortTableEntry.InBytes() << endl;
  os << "\t\toutpkts: " <<  artsPortTableEntry.OutPkts() << endl;
  os << "\t\toutbytes: " << artsPortTableEntry.OutBytes() << endl;
  return(os);
}

//---------------------------------------------------------------------------
//    bool ArtsPortEntryGreaterBytes::operator ()
//                        (const ArtsPortTableEntry & portEntry1,
//                         const ArtsPortTableEntry & portEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool
ArtsPortEntryGreaterBytes::operator () (const ArtsPortTableEntry & portEntry1,
                                        const ArtsPortTableEntry & portEntry2) const
{
  if ((portEntry1.InBytes() + portEntry1.OutBytes()) >
      (portEntry2.InBytes() + portEntry2.OutBytes())) {
    return(true);
  }
  return(false);
}

//---------------------------------------------------------------------------
//    bool  ArtsPortEntryGreaterPkts::operator ()
//                         (const ArtsPortTableEntry & portEntry1,
//                          const ArtsPortTableEntry & portEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool
ArtsPortEntryGreaterPkts::operator () (const ArtsPortTableEntry & portEntry1,
                                       const ArtsPortTableEntry & portEntry2) const
{
  if ((portEntry1.InPkts() + portEntry1.OutPkts()) >
      (portEntry2.InPkts() + portEntry2.OutPkts())) {
    return(true);
  }
  return(false);
}

uint32_t ArtsPortTableEntry::_numObjects = 0;
