//===========================================================================
//  @(#) $Name: arts++-1-1-a12 $
//  @(#) $Id: ArtsInterfaceMatrixAggregator.cc,v 1.2 2004/04/21 23:51:32 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 "ArtsInterfaceMatrixAggregator.hh"

using namespace std;

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

//-------------------------------------------------------------------------
//         bool ArtsInterfaceMatrixKeyValue::                      
//         operator < (const ArtsInterfaceMatrixKeyValue keyValue) const 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool ArtsInterfaceMatrixKeyValue::
operator < (const ArtsInterfaceMatrixKeyValue keyValue) const
{
  if (this->src < keyValue.src)
    return(true);
  if (this->src > keyValue.src)
    return(false);
  
  if (this->dst < keyValue.dst)
    return(true);
  if (this->dst > keyValue.dst)
    return(false);

  return(false);
}

//---------------------------------------------------------------------------
//        bool ArtsInterfaceMatrixKeyValue::
//        operator == (const ArtsInterfaceMatrixKeyValue keyValue) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool ArtsInterfaceMatrixKeyValue::
operator == (const ArtsInterfaceMatrixKeyValue keyValue) const
{
  if (this->src == keyValue.src &&
      this->dst == keyValue.dst)
    return(true);
  return(false);
}

//-------------------------------------------------------------------------
//   ArtsInterfaceMatrixAggregator::ArtsInterfaceMatrixAggregator(const Arts & arts)   
//.........................................................................
//  
//-------------------------------------------------------------------------
ArtsInterfaceMatrixAggregator::ArtsInterfaceMatrixAggregator(const Arts & arts)
{
  assert(arts.Header().Identifier() == artsC_OBJECT_INTERFACE_MATRIX);
  
  this->_header = arts.Header();

  vector<ArtsAttribute>::const_iterator    inAttribute;

  for (inAttribute = arts.Attributes().begin();
       inAttribute != arts.Attributes().end(); inAttribute++) {
    this->_attributes.push_back(*inAttribute);
  }

  counter_t               interfaceMatrixCounter;
  ArtsInterfaceMatrixKeyValue   key;
  vector<ArtsInterfaceMatrixEntry>::const_iterator  inInterfaceMatrixEntry;
  
  for (inInterfaceMatrixEntry = arts.InterfaceMatrixData()->InterfaceEntries().begin();
       inInterfaceMatrixEntry != arts.InterfaceMatrixData()->InterfaceEntries().end();
       inInterfaceMatrixEntry++) {
    key.src = inInterfaceMatrixEntry->Src();
    key.dst = inInterfaceMatrixEntry->Dst();
    
    interfaceMatrixCounter.Pkts = inInterfaceMatrixEntry->Pkts();
    interfaceMatrixCounter.Bytes = inInterfaceMatrixEntry->Bytes();
    this->_interfaceCounters[key] = interfaceMatrixCounter;
  }
  this->_totalPkts = arts.InterfaceMatrixData()->TotalPkts();
  this->_totalBytes = arts.InterfaceMatrixData()->TotalBytes();
}

//-------------------------------------------------------------------------
//           void ArtsInterfaceMatrixAggregator::Add(const Arts & arts)          
//.........................................................................
//  
//-------------------------------------------------------------------------
void ArtsInterfaceMatrixAggregator::Add(const Arts & arts)
{
  assert(arts.Header().Identifier() == artsC_OBJECT_INTERFACE_MATRIX);

  vector<ArtsAttribute>::iterator          myHostAttribute;

  for (myHostAttribute = this->_attributes.begin();
         myHostAttribute != this->_attributes.end();
         myHostAttribute++) {
    if (myHostAttribute->Identifier() == artsC_ATTR_HOST)
      break;
  }
  
  vector<ArtsAttribute>::iterator          myPeriodAttribute;
  vector<ArtsAttribute>::const_iterator    inPeriodAttribute;
  
  for (myPeriodAttribute = this->_attributes.begin();
         myPeriodAttribute != this->_attributes.end();
         myPeriodAttribute++) {
    if (myPeriodAttribute->Identifier() == artsC_ATTR_PERIOD)
      break;
  }
  
  inPeriodAttribute = arts.FindPeriodAttribute();

  const uint32_t *myPeriod = myPeriodAttribute->Period();
  const uint32_t *inPeriod = inPeriodAttribute->Period();
  
  if (inPeriod[0] < myPeriod[0]) {
    myPeriodAttribute->Period(inPeriod[0],myPeriod[1]);
  }
  if (inPeriod[1] > myPeriod[1]) {
    myPeriodAttribute->Period(myPeriod[0],inPeriod[1]);
  }
    
  counter_t               interfaceCounter;
  ArtsInterfaceMatrixKeyValue   key;
  vector<ArtsInterfaceMatrixEntry>::const_iterator        inInterfaceEntry;
  map<ArtsInterfaceMatrixKeyValue,counter_t,less<ArtsInterfaceMatrixKeyValue> >::iterator   myInterfaceEntry;

  for (inInterfaceEntry = arts.InterfaceMatrixData()->InterfaceEntries().begin();
       inInterfaceEntry != arts.InterfaceMatrixData()->InterfaceEntries().end();
       inInterfaceEntry++) {
    key.src = inInterfaceEntry->Src();
    key.dst = inInterfaceEntry->Dst();
    
    myInterfaceEntry = this->_interfaceCounters.find(key);
    if (myInterfaceEntry != this->_interfaceCounters.end()) {
      (*myInterfaceEntry).second.Pkts += inInterfaceEntry->Pkts();
      (*myInterfaceEntry).second.Bytes += inInterfaceEntry->Bytes();
    }
    else {
      interfaceCounter.Pkts = inInterfaceEntry->Pkts();
      interfaceCounter.Bytes = inInterfaceEntry->Bytes();
      this->_interfaceCounters[key] = interfaceCounter;
    }
  }
  this->_totalPkts += arts.InterfaceMatrixData()->TotalPkts();
  this->_totalBytes += arts.InterfaceMatrixData()->TotalBytes();

  return;
}

//-------------------------------------------------------------------------
//  ArtsInterfaceMatrix *
//  ArtsInterfaceMatrixAggregator::ConvertToArtsInterfaceMatrix() const 
//.........................................................................
//  
//-------------------------------------------------------------------------
ArtsInterfaceMatrix *
ArtsInterfaceMatrixAggregator::ConvertToArtsInterfaceMatrix() const
{
  ArtsInterfaceMatrixEntry  interfaceEntry;
  map<ArtsInterfaceMatrixKeyValue,counter_t,
      less<ArtsInterfaceMatrixKeyValue> >::const_iterator  interfaceCounter;

  ArtsInterfaceMatrix *artsInterfaceMatrix = new ArtsInterfaceMatrix();

  artsInterfaceMatrix->Header() = this->_header;
  vector<ArtsAttribute>::const_iterator   inAttribute;

  for (inAttribute = this->_attributes.begin();
       inAttribute != this->_attributes.end(); inAttribute++) {
    artsInterfaceMatrix->Attributes().push_back(*inAttribute);
  }

  uint64_t  totalPkts = 0;
  uint64_t  totalBytes = 0;
  
  for (interfaceCounter = this->_interfaceCounters.begin();
       interfaceCounter != this->_interfaceCounters.end(); interfaceCounter++) {
    interfaceEntry.Src((*interfaceCounter).first.src);
    interfaceEntry.Dst((*interfaceCounter).first.dst);
    interfaceEntry.Pkts((*interfaceCounter).second.Pkts);
    interfaceEntry.Bytes((*interfaceCounter).second.Bytes);
    artsInterfaceMatrix->InterfaceEntries().push_back(interfaceEntry);
    totalPkts += interfaceEntry.Pkts();
    totalBytes += interfaceEntry.Bytes();
  }
  artsInterfaceMatrix->TotalPkts(totalPkts);
  artsInterfaceMatrix->TotalBytes(totalBytes);
  
  return(artsInterfaceMatrix);
}

//-------------------------------------------------------------------------
//     vector<ArtsInterfaceMatrixEntry> *                       
//     ArtsInterfaceMatrixAggregator::TopSourcesByBytes(uint16_t numSources) 
//.........................................................................
//  
//-------------------------------------------------------------------------
vector<ArtsInterfaceMatrixEntry> *
ArtsInterfaceMatrixAggregator::TopSourcesByBytes(uint16_t numSources)
{
  map<uint16_t,counter_t,less<uint16_t> >  srcInterfaceMap;
  map<ArtsInterfaceMatrixKeyValue,counter_t,less<ArtsInterfaceMatrixKeyValue> >::iterator aggMapIter;
  
  //  load a map keyed by source INTERFACE, with a counter_t as the value.
  map<uint16_t,counter_t,less<uint16_t> >::iterator  srcInterfaceMapIter;
  for (aggMapIter = this->_interfaceCounters.begin();
       aggMapIter != this->_interfaceCounters.end(); aggMapIter++) {
    srcInterfaceMapIter = srcInterfaceMap.find((*aggMapIter).first.src);
    if (srcInterfaceMapIter == srcInterfaceMap.end()) {
      srcInterfaceMap[(*aggMapIter).first.src].Pkts = (*aggMapIter).second.Pkts;
      srcInterfaceMap[(*aggMapIter).first.src].Bytes = (*aggMapIter).second.Bytes;
    }
    else {
      (*srcInterfaceMapIter).second.Pkts += (*aggMapIter).second.Pkts;
      (*srcInterfaceMapIter).second.Bytes += (*aggMapIter).second.Bytes;
    }
  }

  //  Now I have a map<uint16_t,counter_t> with src INTERFACE as key and
  //  counter_t as value.  Put it in a vector of ArtsInterfaceMatrixEntry
  //  so I can sort it by byte count.
  ArtsInterfaceMatrixEntry           srcInterfaceEntry;
  vector<ArtsInterfaceMatrixEntry>   srcInterfaceVector;

  srcInterfaceVector.reserve(srcInterfaceMap.size());
  map<uint16_t,counter_t,less<uint16_t> >::iterator  srcMapIter;
  
  for (srcMapIter = srcInterfaceMap.begin();
       srcMapIter != srcInterfaceMap.end(); srcMapIter++) {
    srcInterfaceEntry.Src((*srcMapIter).first);
    srcInterfaceEntry.Dst(0);
    srcInterfaceEntry.Pkts((*srcMapIter).second.Pkts);
    srcInterfaceEntry.Bytes((*srcMapIter).second.Bytes);
    srcInterfaceVector.push_back(srcInterfaceEntry);
  }

  // now sort the vector by the byte counters.
  sort(srcInterfaceVector.begin(),srcInterfaceVector.end(),
       ArtsInterfaceMatrixEntryGreaterBytes());

  //  build the final vector we wish to return.
  vector<ArtsInterfaceMatrixEntry>  *retVector;

  if (srcInterfaceVector.size() < numSources)
    numSources = srcInterfaceVector.size();
  
  retVector = new vector<ArtsInterfaceMatrixEntry>(srcInterfaceVector.begin(),
                                            srcInterfaceVector.begin() + numSources);
  return(retVector);
}


//-------------------------------------------------------------------------
//   vector<ArtsInterfaceMatrixEntry> *                       
//   ArtsInterfaceMatrixAggregator::TopDestinationsByBytes(uint16_t numDests) 
//.........................................................................
//  
//-------------------------------------------------------------------------
vector<ArtsInterfaceMatrixEntry> *
ArtsInterfaceMatrixAggregator::TopDestinationsByBytes(uint16_t numDests)
{
  map<uint16_t,counter_t,less<uint16_t> >  dstInterfaceMap;
  map<ArtsInterfaceMatrixKeyValue,counter_t,less<ArtsInterfaceMatrixKeyValue> >::iterator aggMapIter;
  
  //  load a map keyed by source INTERFACE, with a counter_t as the value.
  map<uint16_t,counter_t,less<uint16_t> >::iterator  dstInterfaceMapIter;
  for (aggMapIter = this->_interfaceCounters.begin();
       aggMapIter != this->_interfaceCounters.end(); aggMapIter++) {
    dstInterfaceMapIter = dstInterfaceMap.find((*aggMapIter).first.dst);
    if (dstInterfaceMapIter == dstInterfaceMap.end()) {
      dstInterfaceMap[(*aggMapIter).first.dst].Pkts = (*aggMapIter).second.Pkts;
      dstInterfaceMap[(*aggMapIter).first.dst].Bytes = (*aggMapIter).second.Bytes;
    }
    else {
      (*dstInterfaceMapIter).second.Pkts += (*aggMapIter).second.Pkts;
      (*dstInterfaceMapIter).second.Bytes += (*aggMapIter).second.Bytes;
    }
  }

  //  Now I have a map<uint16_t,counter_t> with dst INTERFACE as key and
  //  counter_t as value.  Put it in a vector of ArtsInterfaceMatrixEntry
  //  so I can sort it by byte count.
  ArtsInterfaceMatrixEntry           dstInterfaceEntry;
  vector<ArtsInterfaceMatrixEntry>   dstInterfaceVector;

  dstInterfaceVector.reserve(dstInterfaceMap.size());
  map<uint16_t,counter_t,less<uint16_t> >::iterator  dstMapIter;
  
  for (dstMapIter = dstInterfaceMap.begin();
       dstMapIter != dstInterfaceMap.end(); dstMapIter++) {
    dstInterfaceEntry.Dst((*dstMapIter).first);
    dstInterfaceEntry.Src(0);
    dstInterfaceEntry.Pkts((*dstMapIter).second.Pkts);
    dstInterfaceEntry.Bytes((*dstMapIter).second.Bytes);
    dstInterfaceVector.push_back(dstInterfaceEntry);
  }

  // now sort the vector by the byte counters.
  sort(dstInterfaceVector.begin(),dstInterfaceVector.end(),
       ArtsInterfaceMatrixEntryGreaterBytes());

  //  build the final vector we wish to return.
  vector<ArtsInterfaceMatrixEntry>  *retVector;

  if (dstInterfaceVector.size() < numDests)
    numDests = dstInterfaceVector.size();
  
  retVector = new vector<ArtsInterfaceMatrixEntry>(dstInterfaceVector.begin(),
                                            dstInterfaceVector.begin() + numDests);
  return(retVector);
}

//-------------------------------------------------------------------------
//            uint64_t ArtsInterfaceMatrixAggregator::TotalPkts() const           
//.........................................................................
//  
//-------------------------------------------------------------------------
uint64_t ArtsInterfaceMatrixAggregator::TotalPkts() const
{
  return(this->_totalPkts);
}

//-------------------------------------------------------------------------
//           uint64_t ArtsInterfaceMatrixAggregator::TotalBytes() const           
//.........................................................................
//  
//-------------------------------------------------------------------------
uint64_t ArtsInterfaceMatrixAggregator::TotalBytes() const
{
  return(this->_totalBytes);
}

//-------------------------------------------------------------------------
//             const vector<ArtsAttribute> & Attributes() const            
//.........................................................................
//  
//-------------------------------------------------------------------------
const vector<ArtsAttribute> & ArtsInterfaceMatrixAggregator::Attributes() const
{
  return(this->_attributes);
}
