//===========================================================================
//  $Name: arts++-1-1-a12 $
//  $Id: ArtsAsMatrixEntry.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
//===========================================================================

extern "C" {
#include <unistd.h>
}

#include <string>

#include "ArtsAsMatrixEntry.hh"
#include "ArtsPrimitive.hh"

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

//-------------------------------------------------------------------------
//                  ArtsAsMatrixEntry::ArtsAsMatrixEntry()                 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsAsMatrixEntry::ArtsAsMatrixEntry()
{
  this->_descriptor = 0;
  this->_src        = 0;
  this->_dst        = 0;
  this->_pkts       = 0;
  this->_bytes      = 0;
  
  #ifndef NDEBUG
    ++ArtsAsMatrixEntry::_numObjects;
  #endif
}

//----------------------------------------------------------------------------
// ArtsAsMatrixEntry::ArtsAsMatrixEntry(const ArtsAsMatrixEntry & asmEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsAsMatrixEntry::ArtsAsMatrixEntry(const ArtsAsMatrixEntry & asmEntry)
{
  this->_descriptor = asmEntry._descriptor;
  this->_src        = asmEntry._src;
  this->_dst        = asmEntry._dst;
  this->_pkts       = asmEntry._pkts;
  this->_bytes      = asmEntry._bytes;

  #ifndef NDEBUG
    ++ArtsAsMatrixEntry::_numObjects;
  #endif
}
  
//----------------------------------------------------------------------------
//                 ArtsAsMatrixEntry::~ArtsAsMatrixEntry()                 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsAsMatrixEntry::~ArtsAsMatrixEntry()
{
  #ifndef NDEBUG
    --ArtsAsMatrixEntry::_numObjects;
  #endif
}

//-------------------------------------------------------------------------
//              uint16_t ArtsAsMatrixEntry::Src(uint16_t src)              
//.........................................................................
//  
//-------------------------------------------------------------------------
uint16_t ArtsAsMatrixEntry::Src(uint16_t src)
{
  this->_src = src;

  if (src > 0xff)
    this->_descriptor = this->_descriptor | 0x01;
  else
    this->_descriptor = this->_descriptor & 0xfe;
  
  return(this->_src);
}


//-------------------------------------------------------------------------
//              uint16_t ArtsAsMatrixEntry::Dst(uint16_t dst)              
//.........................................................................
//  
//-------------------------------------------------------------------------
uint16_t ArtsAsMatrixEntry::Dst(uint16_t dst)
{
  this->_dst = dst;
  if (dst > 0xff)
    this->_descriptor = this->_descriptor | 0x02;
  else
    this->_descriptor = this->_descriptor & 0xfd;
  
  return(this->_dst);
}

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

  if (pkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor | 0x1c);
  } else if (pkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xe3) | (0x0003 << 2);
  } else if (pkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xe3) | (0x0001 << 2);
  } else {
    this->_descriptor = (this->_descriptor & 0xe3);
  }
  return(this->_pkts);
}

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

  if (bytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor | 0xe0);
  } else if (bytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0x1f) | (0x0003 << 5);
  } else if (bytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0x1f) | (0x0001 << 5);
  } else {
    this->_descriptor = (this->_descriptor & 0x1f);
  }
  return(this->_bytes);
}

//-------------------------------------------------------------------------
//    uint32_t ArtsAsMatrixEntry::Length(uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
uint32_t ArtsAsMatrixEntry::Length(uint8_t version) const
{
  uint32_t   length;

  length = (sizeof(this->_descriptor) +
            (this->_descriptor & 0x01) + 1 +
            ((this->_descriptor >> 1) & 0x01) + 1 +
            ((this->_descriptor >> 2) & 0x07) + 1 +
            ((this->_descriptor >> 5) & 0x07) + 1);
  return(length);
}

//-------------------------------------------------------------------------
//   std::istream& ArtsAsMatrixEntry::read(std::istream& is, uint8_t version)
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::istream& ArtsAsMatrixEntry::read(std::istream& is, uint8_t version)
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize;
  
  is.read((char*)&this->_descriptor,sizeof(this->_descriptor));

  srcsize = (this->_descriptor & 0x01) + 1;
  dstsize  = ((this->_descriptor >> 1) & 0x01) + 1;
  pktsize  = ((this->_descriptor >> 2) & 0x07) + 1;
  bytesize = ((this->_descriptor >> 5) & 0x07) + 1;

  g_ArtsLibInternal_Primitive.ReadUint16(is,this->_src,srcsize);
  g_ArtsLibInternal_Primitive.ReadUint16(is,this->_dst,dstsize);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_pkts,pktsize);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_bytes,bytesize);

  return(is);
}

//-------------------------------------------------------------------------
//         int ArtsAsMatrixEntry::read(int fd, uint8_t version)
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsAsMatrixEntry::read(int fd, uint8_t version)
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize;
  int            rc;
  int            bytesRead = 0;

  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_descriptor,
                                          sizeof(this->_descriptor));
  if (rc != sizeof(this->_descriptor)) {
    return(-1);
  }
  bytesRead += rc;

  srcsize  = (this->_descriptor & 0x01) + 1;
  dstsize  = ((this->_descriptor >> 1) & 0x01) + 1;
  pktsize  = ((this->_descriptor >> 2) & 0x07) + 1;
  bytesize = ((this->_descriptor >> 5) & 0x07) + 1;

  rc = g_ArtsLibInternal_Primitive.ReadUint16(fd,this->_src,srcsize);
  if (rc != srcsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadUint16(fd,this->_dst,dstsize);
  if (rc != dstsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_pkts,pktsize);
  if (rc != pktsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_bytes,bytesize);
  if (rc != bytesize) {
    return(-1);
  }
  bytesRead += rc;

  return(bytesRead);
}

//-------------------------------------------------------------------------
// std::ostream& ArtsAsMatrixEntry::write(std::ostream& os, uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::ostream & ArtsAsMatrixEntry::write(std::ostream & os, uint8_t version) const
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize;

  os.write((char*)&this->_descriptor,sizeof(this->_descriptor));

  srcsize = (this->_descriptor & 0x01) + 1;
  dstsize  = ((this->_descriptor >> 1) & 0x01) + 1;
  pktsize  = ((this->_descriptor >> 2) & 0x07) + 1;
  bytesize = ((this->_descriptor >> 5) & 0x07) + 1;

  g_ArtsLibInternal_Primitive.WriteUint16(os,this->_src,srcsize);
  g_ArtsLibInternal_Primitive.WriteUint16(os,this->_dst,dstsize);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_pkts,pktsize);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_bytes,bytesize);

  return(os);
}

//-------------------------------------------------------------------------
//     int ArtsAsMatrixEntry::write(int fd, uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsAsMatrixEntry::write(int fd, uint8_t version) const
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize;
  int            rc;
  int            bytesWritten = 0;

  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_descriptor,
                                           sizeof(this->_descriptor));
  if (rc !=  sizeof(this->_descriptor)) {
    return(-1);
  }
  bytesWritten += rc;

  srcsize = (this->_descriptor & 0x01) + 1;
  dstsize  = ((this->_descriptor >> 1) & 0x01) + 1;
  pktsize  = ((this->_descriptor >> 2) & 0x07) + 1;
  bytesize = ((this->_descriptor >> 5) & 0x07) + 1;

  rc = g_ArtsLibInternal_Primitive.WriteUint16(fd,this->_src,srcsize);
  if (rc != srcsize) {
    return(-1);
  }
  bytesWritten += rc;
  
  rc = g_ArtsLibInternal_Primitive.WriteUint16(fd,this->_dst,dstsize);
  if (rc != dstsize) {
    return(-1);
  }
  bytesWritten += rc;

  rc = g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_pkts,pktsize);
  if (rc != pktsize) {
    return(-1);
  }
  bytesWritten += rc;

  rc = g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_bytes,bytesize);
  if (rc != bytesize) {
    return(-1);
  }
  bytesWritten += rc;

  return(bytesWritten);
}

//-------------------------------------------------------------------------
//   std::ostream & operator << (std::ostream& os,                   
//                          const ArtsAsMatrixEntry & artsAsMatrixEntry) 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::ostream & operator << (std::ostream& os,
                       const ArtsAsMatrixEntry & artsAsMatrixEntry)
{
  using namespace std;
  os << "\tAS MATRIX ENTRY" << endl;
  os << "\t\tdescriptor: " << (int)artsAsMatrixEntry.Descriptor() << endl;
  os << "\t\tsrc: " << artsAsMatrixEntry.Src() << endl;
  os << "\t\tdst: " << artsAsMatrixEntry.Dst() << endl;
  os << "\t\tpkts: " << artsAsMatrixEntry.Pkts() << endl;
  os << "\t\tbytes: " << artsAsMatrixEntry.Bytes() << endl;

  return(os);
}

//---------------------------------------------------------------------------
//        bool ArtsAsMatrixEntryGreaterBytes::
//        operator () (const ArtsAsMatrixEntry & asEntry1,
//                     const ArtsAsMatrixEntry & asEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool ArtsAsMatrixEntryGreaterBytes::
operator () (const ArtsAsMatrixEntry & asEntry1,
             const ArtsAsMatrixEntry & asEntry2) const
{
  return(asEntry1.Bytes() > asEntry2.Bytes());
}

//---------------------------------------------------------------------------
//        bool ArtsAsMatrixEntryGreaterPkts::
//        operator () (const ArtsAsMatrixEntry & asEntry1,
//                     const ArtsAsMatrixEntry & asEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool ArtsAsMatrixEntryGreaterPkts::
operator () (const ArtsAsMatrixEntry & asEntry1,
             const ArtsAsMatrixEntry & asEntry2) const
{
  return(asEntry1.Pkts() > asEntry2.Pkts());
}

uint32_t ArtsAsMatrixEntry::_numObjects = 0;
