//===========================================================================
//  @(#) $Name: arts++-1-1-a12 $
//  @(#) $Id: ArtsAttribute.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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>

#include "artslocal.h"
#include "caida_t.h"
}

#include <string>
#ifdef HAVE_IOMANIP
  #include <iomanip>
#else
  #include <iomanip.h>
#endif

#include "ArtsAttribute.hh"
#include "ArtsPrimitive.hh"

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

//-------------------------------------------------------------------------
//                      ArtsAttribute::ArtsAttribute()                     
//.........................................................................
//  constructor
//-------------------------------------------------------------------------
ArtsAttribute::ArtsAttribute()
{
  this->_identifier = 0;
  this->_format = 0;
  this->_length = 0;
  memset(&(this->_value),0,sizeof(this->_value));
  this->_value.comment = (std::string *)0;
  this->_value.ifDescr = (std::string *)0;
  this->_value.arbitrary = (std::string *)0;
  
  #ifndef NDEBUG
    ++_numObjects;
  #endif
}

ArtsAttribute::ArtsAttribute(const ArtsAttribute & artsAttribute)
{
  this->_identifier = artsAttribute.Identifier();
  this->_format = artsAttribute.Format();
  this->_length = artsAttribute.Length();

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      this->_value.comment = new std::string(artsAttribute.Comment());
      break;
    case artsC_ATTR_IFDESCR:
      this->_value.ifDescr = new std::string(artsAttribute.IfDescr().c_str());
      break;
    case artsC_ATTR_CREATION:
      this->_value.creation = artsAttribute.Creation();
      break;
    case artsC_ATTR_PERIOD:
      memcpy(this->_value.period,artsAttribute.Period(),
             sizeof(this->_value.period[0]) * 2);
      break;
    case artsC_ATTR_HOST:
      this->_value.host = artsAttribute.Host();
      break;
    case artsC_ATTR_IFINDEX:
      this->_value.ifIndex = artsAttribute.IfIndex();
      break;
    case artsC_ATTR_IFIPADDR:
      this->_value.ifIpAddr = artsAttribute.IfIpAddr();
      break;
    case artsC_ATTR_HOSTPAIR:
      this->_value.hostPair[0] = artsAttribute.HostPair()[0];
      this->_value.hostPair[1] = artsAttribute.HostPair()[1];
      break;
    default:
      break;
  }
}

//-------------------------------------------------------------------------
//     ArtsAttribute &
//     ArtsAttribute::operator = (const ArtsAttribute & artsAttribute) 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsAttribute &
ArtsAttribute::operator = (const ArtsAttribute & artsAttribute)
{
  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      if (this->_value.comment != (std::string *)0) {
        delete(this->_value.comment);
        this->_value.comment = (std::string *)0;
      }
      break;
    case artsC_ATTR_IFDESCR:
      if (this->_value.ifDescr != (std::string *)0) {
        delete(this->_value.ifDescr);
        this->_value.ifDescr = (std::string *)0;
      }
      break;
    default:
      break;
  }
            
  this->_identifier = artsAttribute.Identifier();
  this->_format = artsAttribute.Format();
  this->_length = artsAttribute.Length();

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      this->_value.comment = new std::string(artsAttribute.Comment());
      break;
    case artsC_ATTR_IFDESCR:
      this->_value.ifDescr = new std::string(artsAttribute.IfDescr().c_str());
      break;
    case artsC_ATTR_CREATION:
      this->_value.creation = artsAttribute.Creation();
      break;
    case artsC_ATTR_PERIOD:
      memcpy(this->_value.period,artsAttribute.Period(),
             sizeof(this->_value.period[0]) * 2);
      break;
    case artsC_ATTR_HOST:
      this->_value.host = artsAttribute.Host();
      break;
    case artsC_ATTR_IFINDEX:
      this->_value.ifIndex = artsAttribute.IfIndex();
      break;
    case artsC_ATTR_IFIPADDR:
      this->_value.ifIpAddr = artsAttribute.IfIpAddr();
      break;
    case artsC_ATTR_HOSTPAIR:
      this->_value.hostPair[0] = artsAttribute.HostPair()[0];
      this->_value.hostPair[1] = artsAttribute.HostPair()[1];
      break;
    default:
      break;
  }
  
  return(*this);
}

//-------------------------------------------------------------------------
//                     ArtsAttribute::~ArtsAttribute()                     
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsAttribute::~ArtsAttribute()
{
  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      if (this->_value.comment != (std::string *)0)
        delete(this->_value.comment);
      break;
    case artsC_ATTR_IFDESCR:
      if (this->_value.ifDescr != (std::string *)0)
        delete(this->_value.ifDescr);
      break;
    default:
      break;
  }

  #ifndef NDEBUG
    if (_numObjects > 0)
      --_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//                uint32_t ArtsAttribute::Identifier() const 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Identifier() const
{
  return(this->_identifier);
}

//----------------------------------------------------------------------------
//         uint32_t ArtsAttribute::Identifier(uint32_t identifier) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Identifier(uint32_t identifier)
{
  this->_identifier = identifier;
  return(this->_identifier);
}

//----------------------------------------------------------------------------
//                  uint8_t ArtsAttribute::Format() const 
//............................................................................
//  
//----------------------------------------------------------------------------
uint8_t ArtsAttribute::Format() const
{
  return(this->_format);
}

//----------------------------------------------------------------------------
//                      uint8_t Format(uint8_t format) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint8_t ArtsAttribute::Format(uint8_t format)
{
  this->_format = format;
  return(this->_format);
}

//----------------------------------------------------------------------------
//                  uint32_t ArtsAttribute::Length() const 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Length() const
{
  return(this->_length);
}

//----------------------------------------------------------------------------
//             uint32_t ArtsAttribute::Length(uint32_t length) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Length(uint32_t length)
{
  this->_length = length;
  return(this->_length);
}

//----------------------------------------------------------------------------
//               const std::string ArtsAttribute::Comment() const 
//............................................................................
//  
//----------------------------------------------------------------------------
const std::string ArtsAttribute::Comment() const
{
  assert(this->Identifier() == artsC_ATTR_COMMENT);
  return(*(this->_value.comment));
}

//----------------------------------------------------------------------------
//                 uint32_t ArtsAttribute::Creation() const 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Creation() const
{
  assert(this->Identifier() == artsC_ATTR_CREATION);
  return(this->_value.creation);
}

//----------------------------------------------------------------------------
//           uint32_t ArtsAttribute::Creation(uint32_t creation) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t ArtsAttribute::Creation(uint32_t creation)
{
  assert(this->Identifier() == artsC_ATTR_CREATION);
  this->_value.creation = creation;
  return(this->_value.creation);
}

//----------------------------------------------------------------------------
//              const uint32_t *ArtsAttribute::Period() const 
//............................................................................
//  
//----------------------------------------------------------------------------
const uint32_t *ArtsAttribute::Period() const
{
  assert(this->Identifier() == artsC_ATTR_PERIOD);
  return(this->_value.period);
}

//----------------------------------------------------------------------------
//  uint32_t *ArtsAttribute::Period(uint32_t startTime, uint32_t endTime) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint32_t *ArtsAttribute::Period(uint32_t startTime, uint32_t endTime)
{
  assert(this->Identifier() == artsC_ATTR_PERIOD);
  this->_value.period[0] = startTime;
  this->_value.period[1] = endTime;
  return(this->_value.period);
}

//----------------------------------------------------------------------------
//                  ipv4addr_t ArtsAttribute::Host() const 
//............................................................................
//  
//----------------------------------------------------------------------------
ipv4addr_t ArtsAttribute::Host() const
{
  assert(this->Identifier() == artsC_ATTR_HOST);
  return(this->_value.host);
}

//----------------------------------------------------------------------------
//             ipv4addr_t ArtsAttribute::Host(ipv4addr_t host) 
//............................................................................
//  
//----------------------------------------------------------------------------
ipv4addr_t ArtsAttribute::Host(ipv4addr_t host)
{
  assert(this->Identifier() == artsC_ATTR_HOST);
  this->_value.host = host;
  return(this->_value.host);
}

//----------------------------------------------------------------------------
//     const ipv4addr_t * ArtsAttribute::HostPair() const 
//............................................................................
//  
//----------------------------------------------------------------------------
const ipv4addr_t * ArtsAttribute::HostPair() const
{
  assert(this->Identifier() == artsC_ATTR_HOSTPAIR);
  return(this->_value.hostPair);
}

//----------------------------------------------------------------------------
//     const ipv4addr_t * ArtsAttribute::HostPair(ipv4addr_t host1, 
//                                                ipv4addr_t host2) 
//............................................................................
//  
//----------------------------------------------------------------------------
const ipv4addr_t * ArtsAttribute::HostPair(ipv4addr_t host1,
                                           ipv4addr_t host2)
{
  assert(this->Identifier() == artsC_ATTR_HOSTPAIR);
  this->_format = artsC_IPV4_ADDRESS_PAIR;
  this->_value.hostPair[0] = host1;
  this->_value.hostPair[1] = host2;
  return(this->_value.hostPair);
}

//----------------------------------------------------------------------------
//              const std::string ArtsAttribute::IfDescr() const 
//............................................................................
//  
//----------------------------------------------------------------------------
const std::string ArtsAttribute::IfDescr() const
{
  assert(this->Identifier() == artsC_ATTR_IFDESCR);
  return(*(this->_value.ifDescr));
}

//----------------------------------------------------------------------------
//        std::string ArtsAttribute::IfDescr(const std::string & ifDescr) 
//............................................................................
//  
//----------------------------------------------------------------------------
std::string ArtsAttribute::IfDescr(const std::string & ifDescr)
{
  assert(this->Identifier() == artsC_ATTR_IFDESCR);

  if (this->_value.ifDescr != (std::string *)0) {
    delete(this->_value.ifDescr);
    this->_value.ifDescr = (std::string *)0;
  }
  this->_value.ifDescr = new std::string(ifDescr.c_str());
  return(*(this->_value.ifDescr));
}


//----------------------------------------------------------------------------
//                 uint16_t ArtsAttribute::IfIndex() const 
//............................................................................
//  
//----------------------------------------------------------------------------
uint16_t ArtsAttribute::IfIndex() const
{
  assert(this->Identifier() == artsC_ATTR_IFINDEX);
  return(this->_value.ifIndex);
}

//----------------------------------------------------------------------------
//            uint16_t ArtsAttribute::IfIndex(uint16_t ifIndex) 
//............................................................................
//  
//----------------------------------------------------------------------------
uint16_t ArtsAttribute::IfIndex(uint16_t ifIndex)
{
  assert(this->Identifier() == artsC_ATTR_IFINDEX);
  this->_value.ifIndex = ifIndex;
  return(this->_value.ifIndex);
}

//----------------------------------------------------------------------------
//                ipv4addr_t ArtsAttribute::IfIpAddr() const 
//............................................................................
//  
//----------------------------------------------------------------------------
ipv4addr_t ArtsAttribute::IfIpAddr() const
{
  assert(this->Identifier() == artsC_ATTR_IFIPADDR);
  return(this->_value.ifIpAddr);
}

//----------------------------------------------------------------------------
//          ipv4addr_t ArtsAttribute::IfIpAddr(ipv4addr_t ipAddr) 
//............................................................................
//  
//----------------------------------------------------------------------------
ipv4addr_t ArtsAttribute::IfIpAddr(ipv4addr_t ipAddr)
{
  assert(this->Identifier() == artsC_ATTR_IFIPADDR);
  this->_value.ifIpAddr = ipAddr;
  return(this->_value.ifIpAddr);
}

//----------------------------------------------------------------------------
//                  void *ArtsAttribute::Arbitrary() const 
//............................................................................
//  
//----------------------------------------------------------------------------
void *ArtsAttribute::Arbitrary() const
{
  return(this->_value.arbitrary);
}

//----------------------------------------------------------------------------
//             void *ArtsAttribute::Arbitrary(void *arbitrary) 
//............................................................................
//  
//----------------------------------------------------------------------------
void *ArtsAttribute::Arbitrary(void *arbitrary)
{
  this->_value.arbitrary = arbitrary;
  return(this->_value.arbitrary);
}

//-------------------------------------------------------------------------
//             std::ostream& ArtsAttribute::write(std::ostream& os) const            
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::ostream& ArtsAttribute::write(std::ostream& os) const
{
  uint32_t     uIntDatum, idAndFormat;
  uint16_t     uShortDatum;
  
  const char*  ptr;

  idAndFormat = (this->_identifier << 8) | this->_format;
  uIntDatum = htonl(idAndFormat);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));

  uIntDatum = htonl(this->_length);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      ptr = this->_value.comment->c_str();
      os.write(ptr,this->_value.comment->length()+1);
      break;
    case artsC_ATTR_CREATION:
      uIntDatum = htonl(this->_value.creation);
      os.write((char*)&uIntDatum,sizeof(uIntDatum));
      break;
    case artsC_ATTR_PERIOD:
      uIntDatum = htonl(this->_value.period[0]);
      os.write((char*)&uIntDatum,sizeof(uIntDatum));
      uIntDatum = htonl(this->_value.period[1]);
      os.write((char*)&uIntDatum,sizeof(uIntDatum));
      break;
    case artsC_ATTR_HOST:
      os.write((char*)&this->_value.host,sizeof(this->_value.host));
      break;
    case artsC_ATTR_IFDESCR:
      ptr = this->_value.ifDescr->c_str();
      os.write(ptr,this->_value.ifDescr->length()+1);
      break;
    case artsC_ATTR_IFINDEX:
      uShortDatum = htons(this->_value.ifIndex);
      os.write((char*)&uShortDatum,sizeof(uShortDatum));
      break;
    case artsC_ATTR_IFIPADDR:
      os.write((char*)&this->_value.ifIpAddr,sizeof(this->_value.ifIpAddr));
      break;
    case artsC_ATTR_HOSTPAIR:
      os.write((char*)&(this->_value.hostPair[0]),sizeof(ipv4addr_t));
      os.write((char*)&(this->_value.hostPair[1]),sizeof(ipv4addr_t));
      break;
    default:
      break;
  }
  return(os);
}

//-------------------------------------------------------------------------
//                  int ArtsAttribute::write(int fd) const                 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsAttribute::write(int fd) const
{
  uint32_t     uIntDatum, idAndFormat;
  uint16_t     uShortDatum;
  const char*  ptr;
  int          rc;
  int          bytesWritten = 0;
  
  idAndFormat = (this->_identifier << 8) | this->_format;
  uIntDatum = htonl(idAndFormat);
  if ((rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,
                                                sizeof(uIntDatum))) <
      (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;

  uIntDatum = htonl(this->_length);
  if ((rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,
                                                sizeof(uIntDatum))) <
      (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      ptr = this->_value.comment->c_str();
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,ptr,this->_value.comment->length()+1);
      if (rc != (int)(this->_value.comment->length()+1)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_CREATION:
      uIntDatum = htonl(this->_value.creation);
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,
                                               sizeof(uIntDatum));
      if (rc != sizeof(uIntDatum)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_PERIOD:
      uIntDatum = htonl(this->_value.period[0]);
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,
                                               sizeof(uIntDatum));
      if (rc != sizeof(uIntDatum)) {
        return(-1);
      }
      bytesWritten += rc;
      uIntDatum = htonl(this->_value.period[1]);
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,
                                               sizeof(uIntDatum));
      if (rc != sizeof(uIntDatum)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_HOST:
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_value.host,
                                               sizeof(this->_value.host));
      if (rc != sizeof(this->_value.host)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_IFDESCR:
      ptr = this->_value.ifDescr->c_str();
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,ptr,this->_value.ifDescr->length()+1);
      if (rc != (int)(this->_value.ifDescr->length()+1)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_IFINDEX:
      uShortDatum = htons(this->_value.ifIndex);
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uShortDatum,
                                               sizeof(uShortDatum));
      if (rc != sizeof(uShortDatum)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_IFIPADDR:
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_value.ifIpAddr,
                                               sizeof(this->_value.ifIpAddr));
      if (rc != sizeof(this->_value.ifIpAddr)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    case artsC_ATTR_HOSTPAIR:
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&(this->_value.hostPair[0]),
                                               sizeof(ipv4addr_t));
      if (rc != sizeof(ipv4addr_t)) {
        return(-1);
      }
      bytesWritten += rc;
      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&(this->_value.hostPair[1]),
                                               sizeof(ipv4addr_t));
      if (rc != sizeof(ipv4addr_t)) {
        return(-1);
      }
      bytesWritten += rc;
      break;
    default:
      break;
  }
  return(bytesWritten);
}

//-------------------------------------------------------------------------
//                std::istream& ArtsAttribute::read(std::istream& is)                
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::istream& ArtsAttribute::read(std::istream& is)
{
  uint32_t  uIntDatum, idAndFormat;
  char*     ptr;

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      if (this->_value.comment != (std::string *)0) {
        delete(this->_value.comment);
        this->_value.comment = (std::string *)0;
      }
      break;
    case artsC_ATTR_IFDESCR:
      if (this->_value.ifDescr != (std::string *)0) {
        delete(this->_value.ifDescr);
        this->_value.ifDescr = (std::string *)0;
      }
      break;
    default:
      break;
  }
  
  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  idAndFormat = ntohl(uIntDatum);
  this->_identifier = idAndFormat >> 8;
  this->_format = idAndFormat & 0xff;

  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  this->_length = ntohl(uIntDatum);

  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      ptr = (char *)malloc(this->_length - (sizeof(uint32_t) * 2));
      assert(ptr);
      memset(ptr,0,this->_length - (sizeof(uint32_t) * 2));
      is.read(ptr,this->_length - (sizeof(uint32_t) * 2));
      this->_value.comment = new std::string(ptr);
      free(ptr);
      break;
    case artsC_ATTR_CREATION:
      is.read((char*)&uIntDatum,sizeof(uIntDatum));
      this->_value.creation = ntohl(uIntDatum);
      break;
    case artsC_ATTR_PERIOD:
      is.read((char*)&uIntDatum,sizeof(uIntDatum));
      this->_value.period[0] = htonl(uIntDatum);
      is.read((char*)&uIntDatum,sizeof(uIntDatum));
      this->_value.period[1] = htonl(uIntDatum);
      break;
    case artsC_ATTR_HOST:
      is.read((char*)&this->_value.host,sizeof(this->_value.host));
      break;
    case artsC_ATTR_IFDESCR:
      ptr = (char *)malloc(this->_length - (sizeof(uint32_t) * 2));
      assert(ptr);
      memset(ptr,0,this->_length - (sizeof(uint32_t) * 2));
      is.read(ptr,this->_length - (sizeof(uint32_t) * 2));
      this->_value.ifDescr = new std::string(ptr);
      free(ptr);
      break;
    case artsC_ATTR_IFINDEX:
      is.read((char*)&this->_value.ifIndex,sizeof(this->_value.ifIndex));
      this->_value.ifIndex = ntohs(this->_value.ifIndex);
      break;
    case artsC_ATTR_IFIPADDR:
      is.read((char*)&this->_value.ifIpAddr,sizeof(this->_value.ifIpAddr));
      break;
    case artsC_ATTR_HOSTPAIR:
      is.read((char*)&(this->_value.hostPair[0]),sizeof(ipv4addr_t));
      is.read((char*)&(this->_value.hostPair[1]),sizeof(ipv4addr_t));
      break;
    default:
      break;
  }

  return(is);
}

//-------------------------------------------------------------------------
//                     int ArtsAttribute::read(int fd)                     
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsAttribute::read(int fd)
{
  uint32_t  uIntDatum, idAndFormat;
  char*     ptr;
  int       rc;
  int       bytesRead = 0;
  
  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  idAndFormat = ntohl(uIntDatum);
  this->_identifier = idAndFormat >> 8;
  this->_format = idAndFormat & 0xff;

  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  
  this->_length = ntohl(uIntDatum);

  int  commentLen, ifDescrLen;
  
  switch (this->_identifier) {
    case artsC_ATTR_COMMENT:
      commentLen = this->_length - (sizeof(uint32_t) * 2);
      ptr = (char *)malloc(commentLen);
      assert(ptr);
      memset(ptr,0,commentLen);
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,ptr,commentLen);
      if (rc < commentLen)
        return(rc);
      bytesRead += rc;
      if (this->_value.comment)
        delete(this->_value.comment);
      this->_value.comment = new std::string(ptr);
      free(ptr);
      break;
    case artsC_ATTR_CREATION:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,
                                              sizeof(uIntDatum));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      this->_value.creation = ntohl(uIntDatum);
      break;
    case artsC_ATTR_PERIOD:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,
                                              sizeof(uIntDatum));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      this->_value.period[0] = htonl(uIntDatum);
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,
                                              sizeof(uIntDatum));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      this->_value.period[1] = htonl(uIntDatum);
      break;
    case artsC_ATTR_HOST:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_value.host,
                                              sizeof(this->_value.host));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      break;
    case artsC_ATTR_IFDESCR:
      ifDescrLen = this->_length - (sizeof(uint32_t) * 2);
      ptr = (char *)malloc(ifDescrLen);
      assert(ptr);
      memset(ptr,0,ifDescrLen);
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,ptr,ifDescrLen);
      if (rc < ifDescrLen)
        return(rc);
      bytesRead += rc;
      if (this->_value.ifDescr != (std::string *)0)
        delete(this->_value.ifDescr);
      this->_value.ifDescr = new std::string(ptr);
      free(ptr);
      break;
    case artsC_ATTR_IFINDEX:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_value.ifIndex,
                                              sizeof(this->_value.ifIndex));
      if (rc <= 0)
        return(rc);
      this->_value.ifIndex = ntohs(this->_value.ifIndex);
      bytesRead += rc;
      break;
    case artsC_ATTR_IFIPADDR:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_value.ifIpAddr,
                                              sizeof(this->_value.ifIpAddr));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      break;
    case artsC_ATTR_HOSTPAIR:
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&(this->_value.hostPair[0]),
                                              sizeof(ipv4addr_t));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&(this->_value.hostPair[1]),
                                              sizeof(ipv4addr_t));
      if (rc <= 0)
        return(rc);
      bytesRead += rc;
      break;
    default:
      break;
  }

  return(bytesRead);
}

//-------------------------------------------------------------------------
//    std::ostream & operator << (std::ostream &os, ArtsAttribute & artsAttribute)   
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
std::ostream & operator << (std::ostream &os, ArtsAttribute & artsAttribute)
{
  struct in_addr  inAddr;
  time_t          timestamp;
  struct tm      *Tm;

  using namespace std;
  
  os << "ATTRIBUTE" << endl;
  switch (artsAttribute.Identifier()) {
    case artsC_ATTR_COMMENT:
      break;
    case artsC_ATTR_CREATION:
      timestamp = artsAttribute.Creation();
      Tm = localtime(&timestamp);
      os << setiosflags(ios::internal);
      os << "\tcreation: " << setfill('0') << setw(2) << Tm->tm_mon+1 << "/"
         << setw(2) << Tm->tm_mday << "/" << setw(4) << Tm->tm_year+1900
         << " " << setw(2) << Tm->tm_hour << ":" << setw(2)
         << Tm->tm_min << ":" << setw(2) << Tm->tm_sec << " ("
         << hex << (int)(artsAttribute.Creation()) << ")" << dec << endl;
      os << setfill(' ');
      break;
    case artsC_ATTR_PERIOD:
      os << "\tperiod: " << dec << artsAttribute.Period()[0] << " "
         << artsAttribute.Period()[1] << endl;
      break;
    case artsC_ATTR_HOST:
      inAddr.s_addr = artsAttribute.Host();
      os << "\thost: " << inet_ntoa(inAddr) << endl;
      break;
    case artsC_ATTR_IFDESCR:
      os << "\tifDescr: " << artsAttribute.IfDescr() << endl;
      break;
    case artsC_ATTR_IFINDEX:
      os << "\tifIndex: " << artsAttribute.IfIndex() << endl;
      break;
    case artsC_ATTR_IFIPADDR:
      inAddr.s_addr = artsAttribute.IfIpAddr();
      os << "\tifIpAddr: " << inet_ntoa(inAddr) << endl;
      break;
    case artsC_ATTR_HOSTPAIR:
      inAddr.s_addr = artsAttribute.HostPair()[0];
      os << "\thostPair: " << inet_ntoa(inAddr);
      inAddr.s_addr = artsAttribute.HostPair()[1];
      os << " " << inet_ntoa(inAddr) << endl;
      break;
    default:
      break;
  }
  return(os);
}

uint32_t  ArtsAttribute::_numObjects = 0;
