/* This version allows number of ingress and egress ports to be different */
/* W. Vanderbauwhede 07/07/2004 */
/*
$Id$
*/
#include <stdlib.h>
#include <iostream>
#include <math.h>
#include <time.h>
#include "opsmodule8.h"
#ifdef MERSENNE_TWISTER
#include "../SOURCES/MersenneTwister.h"
#endif
//#if KEEP_ORDER == 1
#include <queue>
//#endif
#include <deque>

using namespace std;

/*
WV 20052003
ADD_DROP: Modification to have a different number of buffers on the ADD port.
see bufsim6, this is not implemented yet
*/

//=============================================================================

// This is nice, but for speed I restrict MAXGW to INT_MAX-1
// INT_MAX == 2147483647
// Worst case this means longest gap is about 10^5 packets. Should be OK.
#if CALCMAXGW == 1
// Average packet length, average duration of the run
//We need this for the gap width calculation:
//A gap width of longer than te duration is useless
//I restrict the gap width to 1% of the duration, ad hoc

// Average packet length
#ifndef AGGREGATE
#if PLDIST == 0
// Square dist for packet length
const int avgpl=NBITSH+UNITPL*(1+NMAX)/2;
#elif PLDIST == 1	
	  //fixed length
const int avgpl=FIXPL;
#elif PLDIST == 2
	  // 50% UNITPL
	  // 30%  UNITPL*NMED
	  // 20% UNITPL*NMAX
const int avgpl=NBITSH+UNITPL*(0.5+0.3*NMED+0.2*NMAX);
#elif PLDIST == 3
// All packets UNITPL=MINPL
const int avgpl=UNITPL+NBITSH;
#elif PLDIST == 4
//All packets MAXPL
const int avgpl=UNITPL*NMAX+NBITSH;
#elif PLDIST == 5
	  // FRACT_MIN UNITPL, 1-FRACT_MIN UNITPL*NMAX
const int avgpl=NBITSH+FRACT_MIN*UNITPL+(1-FRACT_MIN)*UNITPL*NMAX;
#elif PLDIST == 6
//IP dist
const int avgpl=2784+NBITSH;
#endif // PLDIST
#else
#if PLDIST == 6
const int avgpl=9120+NBITSH;
#else
//ad hoc
const int avgpl=MAXPL/2+NBITSH;
#endif // PLDIST
#endif // AGGREGATE

const long long avgduration=(avgpl+MEANGW)*NPACK;
const int maxgw=(int)(avgduration/100);

#else
const int maxgw = INT_MAX-2;
#endif // CALCMAXGW

//const int maxgw = INT_MAX-2;
//-----------------------------------------------------------------------------

#ifdef MERSENNE_TWISTER
MTRand mtrand;
MTRand * p_mtrand = &mtrand;
#endif // MERSENNE_TWISTER

inline double myrand (void) {
  //  cout << "Calling myrand() "<<ntimes<<"\n";
double r; 
// MTRand mtrand = *p_mtrand;
#ifndef MERSENNE_TWISTER
 /* random value in range [0,1] */
 r = ( (double)rand() / (double)(RAND_MAX) );
#else
/* random value in range [0,1[, Mersenne Twister generator */
  r = (*p_mtrand).randExc();
#endif // MERSENNE_TWISTER
return(r);

}

//-----------------------------------------------------------------------------

inline double pareto (double k,double m,int maxgw) {
  //  cout << "Calling pareto()\n";
// Generate Pareto random numbers
    // k between 1 and 2, closer to 1 means more long periods
    // m is the minimum value for the period, e.g. the number of packets in the burst.
  //  double y=maxgw+1;
  double y=m/pow(1-myrand(),1/k);
  // mean=1st moment=m*k/(k-1) => k= mean/(mean-m)
  // median = m*(2**(1/k)), this is 50th percentile
  while(y>=maxgw){
  y=m/pow(1-myrand(),1/k); //This is based on F^-1, not f^-1!
  }   
  return(y);

}
//-----------------------------------------------------------------------------
inline int poisson (int maxgw,int mingw, int meangw) {
  //  cout << "Calling poisson()\n";
// Generate Poisson random numbers
// Poisson dist for gap width
// (1/lambda)*exp(-(x-mu)/lambda)
// 1/lambda=mu=MINGW
// median = 1/lambda*ln(2) + mu
// 1-myrand() because myrand() can be 0
// int gap=(int)(-log(1-myrand())*MINGW)+MINGW;

  //int y=maxgw+1;
  int y = (int)(-log(1-myrand())*(meangw-mingw))+mingw;

  while(y>maxgw){
    y=(int)(-log(1-myrand())*(meangw-mingw))+mingw;
  }
  return(y);

}
//-----------------------------------------------------------------------------

inline int uniform (int maxgw,int mingw, int meangw) {
  //  cout << "Calling uniform()\n";
  //Uniform distribution based on average and min
  int y=maxgw+1;
  while(y>maxgw){
    y=mingw+(int)(2*(meangw-mingw)*myrand());
  }
  return(y);
}
//-----------------------------------------------------------------------------

inline int packetlength () {
  //  cout << "Calling packetlength()\n";
  // 1.1. Generate packets      
  int length=UNITPL;
	
#ifdef AGGREGATE
  int aggregated_length=0;
  while(aggregated_length<MAXPL) {
    int tmplength;
#else
  int tmplength=UNITPL;
#endif // AGGREGATE

#if PLDIST == 0
	  // Square dist for packet length
	  tmplength=NBITSH+UNITPL*(1+(int)(NMAX*myrand()));
#elif PLDIST == 1	
	  //fixed length
	  tmplength=FIXPL;
#elif PLDIST == 2
	  // this probably makes more sense, in IP traffic:
	  // 50% UNITPL
	  // 30%  UNITPL*NMED
	  // 20% UNITPL*NMAX
	  // Average: UNITPL*(0.5+0.3*NMED+0.2*NMAX)
	  double lengthrand=myrand();
	  if (lengthrand<0.2) {
	    tmplength=UNITPL*NMAX+NBITSH;
	  }  else {
	    if (lengthrand>0.7) {
	      tmplength=UNITPL*NMED+NBITSH;
	    } else {
	      tmplength=UNITPL+NBITSH;
	    }
	  } 
#elif PLDIST == 3
	  tmplength=UNITPL+NBITSH;
#elif PLDIST == 4
	  tmplength=UNITPL*NMAX+NBITSH;
#elif PLDIST == 5
	  // FRACT_MIN UNITPL, 1-FRACT_MIN UNITPL*NMAX
	  double lengthrand=myrand();
	  if (lengthrand>FRACT_MIN) {
	    tmplength=UNITPL*NMAX+NBITSH;
	  }  else {
	    tmplength=UNITPL+NBITSH;
	  } 
#elif PLDIST == 6
	  //more accurate IP packet length distribution:
	  //from http://www.caida.org/analysis/AIX/plen_hist/000221-000227_cumhist.gif
	  double lengthrand=myrand();
	  if (lengthrand<0.5) {  
	    //0<lengthrand<0.5: 
	    tmplength=NBITSH+UNITPL;
	  } else {
	    if(lengthrand<0.6){ 
	      //0.5<lengthrand<0.6: 
	      tmplength=(int)(NBITSH+UNITPL*(40+(lengthrand-0.5)*512/0.1)/40);
	    } else {
	      if(lengthrand<0.65) {
		//0.6<lengthrand<0.65:  
		tmplength=(int)(NBITSH+552*UNITPL/40);
	      } else {
		if(lengthrand<0.85){
		  //0.65<lengthrand<0.85:  
		  tmplength=(int)(NBITSH+576*UNITPL/40);
		} else {
		  //0.85<lengthrand<1.0:  
		  tmplength=(int)(NBITSH+(576+(lengthrand-0.85)*924/0.15)*UNITPL/40);
		}
	      }
	    }
	  }
#endif // PLDIST 0..6

#ifdef AGGREGATE
	  length=aggregated_length;
	  aggregated_length+=tmplength;
	}
#else
	length=tmplength;
#endif // AGGREGATE
	return(length);
}
//-----------------------------------------------------------------------------

inline int gapwidth (int maxgw) {
  //  cout << "Calling gapwidth()\n";
      // 1.2. Generate gaps      
#if TRAFDIST == 0
	// Poisson dist for gap width
	int gap=poisson(maxgw,MINGW,MEANGW);
	
#elif TRAFDIST == 1
	// Pareto dist for gap width:
	const double k_pareto=K_PARETO;
	int gap=(int)pareto(k_pareto,MINGW,maxgw);
#elif TRAFDIST == 2
	//Uniform idstribution based on average and min
	int gap=uniform(maxgw,MINGW,MEANGW);
#elif TRAFDIST == 3
	//Fixed gap width
	int gap=FIXGW;
#endif // TRAFDIST 0/1/2
  return(gap);
}
//------------------------------------------------------------------------------
#ifdef PACKET_TRAINS
inline int packettrainlength () {

	  //Generate length of next packet train
#ifdef TRAIN_LENGTH_DIST
#if TRAIN_LENGTH_DIST == 0
	  //use poisson
	  int inttrainlength = poisson(MAXTRAINL,1,MEANTRAINL)-1;
#elif TRAIN_LENGTH_DIST == 1
	  //use pareto
	  const double k_pareto_train=K_PARETO_TRAIN;
	  int inttrainlength =(int)pareto(k_pareto_train,1,MAXTRAINL)-1;
#elif TRAIN_LENGTH_DIST == 2
	  //use uiform
	  int inttrainlength = uniform(MAXTRAINL,1,MEANTRAINL)-1;
#endif // TRAIN_LENGTH_DIST 0/1/2
#else
	  //use poisson
	  int inttrainlength = poisson(MAXTRAINL,1,MEANTRAINL)-1;
#endif // TRAIN_LENGTH_DIST
	  return(inttrainlength);
}
#endif // PACKET_TRAINS
//================================================================================

int main() {

  //================ Declarations and initialisations ================
/* 
ingress ports: NPORTS
egress ports: NDESTS
*/

  long long tt=2; // this is the main time counter
#ifdef DIFFSERV
//  unsigned int dropcount_class[6]={0,0,0,0,0,0};
// It is more important to see the intra-AF drop behaviour than the different AF's
// So the usefull classes should be EF, AFi0,AFi1,AFi2, BE
// So we need only 5 
  unsigned int dropcount_class[5]={0,0,0,0,0};
  const int pct_EF= PCT_EF;
  const int pct_AF= PCT_AF;
  const int pct_AF_HI = PCT_AF_HI;
  const int pct_AF_LO = PCT_AF_LO;
#endif // DIFFSERV
  unsigned int dropcount=0;

  unsigned int spacketcount=0;
  unsigned int packetcount=0;
#ifdef EQUALISE
  int please_wait[NPORTS];
#endif // EQUALISE
#ifdef RECIRC
  int rpacketlength=0; // recycled length
  int rgapwidth=0; // recycled gap
//  queue<int> rpackets[NPORTS][2];  
  queue<int> rpackets[NDESTS][2];  
  int a_lg[2];
#endif // RECIRC

#ifdef PACKET_TRAINS
int traincounter[NPORTS];
int trainlength[NPORTS];
int traindest[NPORTS];
int intrain[NPORTS];
#endif // PACKET_TRAINS

// wait is a simple array to keep track of the time to wait between packets
long long wait[NPORTS];

// buffer is a "plain" 3D array. 
 long long buffer[NPORTS][NBUFS][5];// the 5th field is for the diffserv class

// portfree is an array of integers, with dimension NPORTS
//takes tt as value somewhere along the road, hence long long
//long long portfree[NPORTS];
// portfree is an array of integers, with dimension NDESTS
long long portfree[NDESTS];

// empty_buffers is an array with the address of every empty buffer.
// This array should grow or shrink on demand!
// but if this is impossible, just define an "empty" value and a condition
// if C++ is really so fast, shouldn't be a problem
#ifdef FIFO
 queue<int> empty_buffers[NPORTS]; 
#else

int empty_buffers[NPORTS][NBUFS];
int index_empty[NPORTS];
#endif // FIFO 

#ifdef HISTS
  long long time_in[NPORTS][NBUFS];
#endif // HISTS
//  long long prev_tt[NPORTS];
  long long prev_tt[NDESTS];

#if KEEP_ORDER ==1
//  queue<int> buffer_stack[NPORTS][NPORTS];
//this is tricky. is it
  queue<int> buffer_stack[NPORTS][NDESTS];
//or
//  queue<int> buffer_stack[NDESTS][NPORTS];
//?
#endif //  KEEP_ORDER 1

#ifdef STATS
#ifndef MERSENNE_TWISTER
  srand(STATS);
#else
  mtrand.seed(STATS);
#endif // MERSENNE_TWISTER
#else 
#ifndef MERSENNE_TWISTER
  srand(4357U);
#else 
  mtrand.seed(4357U);
#endif // MERSENNE_TWISTER
#endif // STATS

#ifdef ONLY_TRAFFIC
  long long  meanlength=0;
  long long meangap=0;
  int minlength=0;
  int maxlength=0;
  int mingap=0;
  int maxgap=0;
#endif // ONLY_TRAFFIC

#ifdef DIFFSERV
  //Additional datastructures for DiffServ
  //EF, AF[4][3], BE
  const int diffservclass[14]={0,11,12,13,21,22,23,31,32,33,41,42,43,50};
  //To keep track of which packet can be dropped
  deque<short int> dropBE[NPORTS];  //always try to drop BE first
  //REUSE ORDER QUEUE! queue<int> dropAF[NPORTS][4][3];  // then try to drop AF in order
  deque<short int> dropAF[NPORTS][4][3];  // then try to drop AF in order
//  deque<short int>  keep_order_EF_AF[NPORTS][NPORTS][5];//EF+AF[4]; BE is not ordered
  deque<short int>  keep_order_EF_AF[NPORTS][NDESTS][5];//EF+AF[4]; BE is not ordered
  //To keep track of which packet has the priority. If an element is >0,it means at least one packet with a higher priority exists in the buffer, so exit is denied.
#ifdef PRIORITISE
  int priority_EF_AF[NPORTS][5]={0,0,0,0,0};
#endif //PRIORITISE
#endif // DIFFSERV

  // cout << "Start init\n";
  //--------------------------------------------------------------------------------
  // Initialisation
  //--------------------------------------------------------------------------------

  for (int i=0;i<NPORTS;i++) {
    //    wait[i]=-1;
    wait[i]=2;
//NDESTS, I think
//    portfree[i]=1;

#ifdef EQUALISE
    please_wait[i]=0;
#endif // EQUALISE
#ifdef PACKET_TRAINS
    traincounter[i]=0;
    trainlength[i]=0;
    traindest[i]=NPORTS;
    intrain[i]=0;
#endif // PACKET_TRAINS
#ifndef FIFO
    index_empty[i]=0;
#endif // FIFO
    
    prev_tt[i]=0;
    
    for (int j=0;j<NBUFS;j++) {
#ifdef FIFO
      empty_buffers[i].push(j);
#else
      empty_buffers[i][j]=j;
#endif // FIFO
      for (int ii=0;ii<5;ii++) {
	buffer[i][j][ii]=-1;
      }
    }
  }

  for (int i=0;i<NDESTS;i++) {
    portfree[i]=1;
  }

  /* 
     The type of buffer is determined by its length:
     plength determines the frequency at which a packet can request to leave the buffer.
     This means the multi-exit buffer is modeled as a very short fixed-length buffer.
  */
  //For All buffer types except the adaptive buffer
#if BUFTYPE == 1
  const int plength=BUFL;  // Buffer with fixed length for worst case:
#elif BUFTYPE == 2
  const int plength=MINGW; // Best case: multi-exit buffer
#elif BUFTYPE == 3
  const int plength=MULTI_EXIT_BUFL; // multi-exit buffer, variable number of exits
#else
  const int plength=MINGW; // Best case: multi-exit buffer
#endif // BUFTYPE 1/2/3
  
  time_t starttime,stoptime;
  time(&starttime); // to check simulation time
  //  cout << "Done init\n";
  //==============================================================================
  //main timing loop
#ifdef DIFFSERV
int dropped[4]={0,0,0,0};
#endif // DIFFSERV
  long long tt_next=0;

  while (packetcount<NPACK) {
    //---------------------------------------------------------------------------
    // Every port is treated separately
    //---------------------------------------------------------------------------

    tt_next=tt+MINGW;

    for (int i=0;i<NPORTS;i++) {

#ifdef FAST
      if(tt>wait[i]) { // time to create a new packet
#else
	if(tt==wait[i]) { // time to create a new packet
#endif // FAST
	  //-----------------------------------------------------------------------------
	  // 1. Generate packets and gaps
	  //-----------------------------------------------------------------------------

	  //When recirculating, the packets are chosen from a random outport
	  //int recircport=i;
#ifdef RECIRC
//		if(packetcount>(RECIRC*NPORTS)) {
		if(packetcount>(RECIRC*NDESTS)) { // RECIRC says when the system starts recycling
#ifndef ADD_DROP
//	    int recircport=(int)(NPORTS*myrand());
	    int recircport=(int)(NDESTS*myrand());
#else
//	    int recircport=(int)((NPORTS-1)*myrand())+1;// can never be 0
	    int recircport=(int)((NDESTS-1)*myrand())+1;// can never be 0
#endif // ADD_DROP
	    //if queue nearly empty, pick another
	    //nearly empty: queue size==MINQL, minimum lenght of the link. 
	    //Rather 'ad hoc' defined as MEANQL/10, i.e. a link of 10km
	    while(rpackets[recircport][0].size()<MINQL) {
//	      recircport=(int)(NPORTS*myrand());	  
	      recircport=(int)(NDESTS*myrand());	  
	    }
	    rpacketlength=rpackets[recircport][0].front();
	    rpackets[recircport][0].pop(); 
	    rgapwidth=rpackets[recircport][1].front();
	    rpackets[recircport][1].pop(); 
	  }
#ifndef ADD_DROP
	  // 1.1. Generate packets   	
//	  int length=(packetcount>RECIRC*NPORTS)?rpacketlength:packetlength();
	  int length=(packetcount>RECIRC*NDESTS)?rpacketlength:packetlength();
	  // 1.2. Generate gaps      
//	  int gap=(packetcount>RECIRC*NPORTS)?rgapwidth:gapwidth(maxgw);
	  int gap=(packetcount>RECIRC*NDESTS)?rgapwidth:gapwidth(maxgw);
#else
	  // 1.1. Generate packets   	
//	  int length=((i>0)&&(packetcount>RECIRC*NPORTS))?rpacketlength:packetlength();
	  int length=((i>0)&&(packetcount>RECIRC*NDESTS))?rpacketlength:packetlength();
	  // 1.2. Generate gaps      
//	  int gap=((i>0)&&(packetcount>RECIRC*NPORTS))?rgapwidth:gapwidth(maxgw);
	  int gap=((i>0)&&(packetcount>RECIRC*NDESTS))?rgapwidth:gapwidth(maxgw);
#endif // ADD_DROP
#else
	  // 1.1. Generate packets   	
	  int length=packetlength();
	  // 1.2. Generate gaps      
	  int gap=gapwidth(maxgw);
#endif // RECIRC

	  // 1.3. Generate destination
	  double destrand=myrand();
//	  int dest=(int)(NPORTS*destrand); //every destination is as likely
	  int dest=(int)(NDESTS*destrand); //every destination is as likely
	  //OVERRIDE DESTINATION: destination=port, so no contention
	  //dest=i;

#ifdef PACKET_TRAINS
	  //Extra code to generate packet trains
	  if(traincounter[i]==trainlength[i]) { // end of train reached
	    traincounter[i]=0;
	    traindest[i] = dest; 
	    trainlength[i]=packettrainlength();
	    gap=MEANGW;
	    //intrain[i]=1;
	  } else { // in train, override gap & dest
	    //Every packet in the train is at MEANGW (a bit 'ad hoc', that.
#ifndef VAR_GW_TRAIN
	    gap=MEANGW;
#endif // VAR_GW_TRAIN
	    //Every packet in the train has the same destination 
	    dest=traindest[i];
	    //(and the same service class)
	    traincounter[i]++;
	  }

#endif // PACKET_TRAINS 

#ifdef DIFFSERV
	  // 1.4. Generate DiffServ Class
	  double classrand=myrand();
	  int packetclassprob=(int)(100*classrand); // 100%
	  /*
	    AD HOC:
	    EF: 5%,
	    AF: 40% in total,means 10% per class
	    BE: the rest

	  */
	 
	  int packetclass=50;
	  if(packetclassprob<=pct_EF){//EF
	    packetclass=0;
	  } else {
	    if(packetclassprob<=pct_EF+4*pct_AF){//AF
		   
		    double AFrand=myrand();// determine AF class and drop level
		    int AFprob=(int)(100*AFrand);
		    int AFclass=(int)(4*myrand()); // 0..3
		    int AFdroplevel=2;
		    if(AFprob<=pct_AF_LO) {
			    AFdroplevel=0;
		    } else {
			    if(AFprob<=100-pct_AF_HI) {
				    AFdroplevel=1;
			    }
		    }
		    int packetclassindex=1+AFclass*3+AFdroplevel;
//int packetclassindex=(int)(12*AFrand+1);// must check if this is 1..12
		    packetclass=diffservclass[packetclassindex];
	    }
	  }
#endif // DIFFSERV

	  wait[i]=tt+length+gap;
	  packetcount++;
	  
#ifdef ONLY_TRAFFIC
	  maxgap=(gap>maxgap)?gap:maxgap;
	  maxlength=(length>maxlength)?length:maxlength;
	  meanlength=meanlength+length;
	  meangap=meangap+gap;
	  if(packetcount==NPACK) {
	    cout <<  packetcount<<":"<<i<<":"<<length<<":"<<gap<<"\t"<<meanlength/packetcount<<":"<<meangap/packetcount<<"\tload: "<< 100*meanlength/(meanlength+meangap)<< "\tmax:"<<maxlength<<":"<<maxgap<<" @"<<tt<<"\n";
	  }
#ifdef HISTS
#ifdef PL
	  if(packetcount>WARMUP) {
	    cout <<"PL"<< i<<"\t"<<tt<<"\t"<<length<<endl;
	  }
#endif //PL
#ifdef GW
	  if(packetcount>WARMUP) {
	    cout <<"GW"<< i<<"\t"<<tt<<"\t"<<gap<<endl;
	  }
#endif //GW
#ifdef DEST
	  if(packetcount>WARMUP) {
	    cout <<"DEST"<< i<<"\t"<<tt<<"\t"<<dest<<endl;
	  }
#endif //DEST
#endif // HISTS
	  //      }
#else
	//------------------------------------------------------------------------------
	// The actual OPS code starts here
	//------------------------------------------------------------------------------
#ifdef HISTS
#ifdef B
	  if(packetcount>WARMUP) {
	    cout <<"B"<< i<<"\t"<<tt<<"\t"<<gap<<endl;
	  }
#endif //B
#endif // HISTS
#ifdef VVERBOSE
	  cout <<  "New packet "<<i<<":"<<tt<<":";
#endif // VVERBOSE
	  // Store in buffer or drop
#ifdef PREEMPTIVE_DROP
#ifdef DIFFSERV
	  //----------------------------------------------------------------------
	  //    Pre-emptive drop of lower-priority packets from buffer
	  //----------------------------------------------------------------------
	  //If packet is not BE, check if full. If so, try to drop another packet instead.
	  int jdrop=NBUFS+1;
	  if(packetclass<50) { // don't check for BE
	    int packetclasstype=(packetclass-(packetclass % 10))/10;
#ifdef FIFO
	    if(empty_buffers[i].empty()) {
#else // not FIFO
	      if (index_empty[i]==NBUFS) { // if NBUFS means all buffers full
#endif // FIFO

		if(dropBE[i].empty()) {// no droppable BE packets found
		  if(packetclass==0) { // EF traffic, drop any AF packet		    
		    int dropped=0;
		    for (int aj=2;aj>=0;aj--) {
		      for (int ai=0;ai<=3;ai++) {
			if(!dropAF[i][ai][aj].empty()) {
			  //drop this packet;
			  jdrop=dropAF[i][ai][aj].front();
#ifdef VERBOSE
			  cout <<"\nPopped "<<jdrop<<" off AF("<<ai<<""<<aj<<")["<<i<<"] ("<<dropAF[i][ai][aj].size()<<") to save and EF packet @"<<tt<<"\n";  
#endif //VERBOSE
			  dropAF[i][ai][aj].pop_front();
//			  dropcount_class[ai+1]++; // 0=EF class
// dropcount per AF drop level
			  dropcount_class[aj+1]++; // 0=EF class
			  dropcount++;
			  dropped=1;
			  break;
			}
		      }
		      if(dropped==1){break;}
		    }		   
		  } else { // AF traffic
		    int packetsubclass=(packetclass % 10);//1..3
		    int ai=(packetclass-packetsubclass)/10-1;//0..3
		    for (int aj=2;aj>=0;aj--) {
		      //if the packet's subclass is 2, it cannot drop 1 or 0, and it's no use dropping another class 2
		      if(packetsubclass>aj){break;}
		      //if the packet's subclass is 0, it can drop 0,1 or 2
		      if(!dropAF[i][ai][aj].empty()) {
			//drop this packet;  
			jdrop=dropAF[i][ai][aj].front();
#ifdef VERBOSE
			cout <<"\nPopped "<<jdrop<<" off AF("<<ai<<""<<aj<<")["<<i<<"] ("<<dropAF[i][ai][aj].size()<<") to save an AF("<<packetclass<<") packet\n";  
#endif //VERBOSE
			dropAF[i][ai][aj].pop_front();  
//			dropcount_class[ai+1]++;
// dropcount per AF drop level
			dropcount_class[aj+1]++;
			dropcount++;
			break;
		      } // found a lower-priority packet
		    } // loop over subclasses
		  } // not EF , so must be AF
		} else { // BE packets in buffer
		  //drop the first BE packet
		  jdrop=dropBE[i].front();
		  dropBE[i].pop_front();
#ifdef VERBOSE
		  cout <<"\nPopped "<<jdrop<<" off BE["<<i<<"] ("<<dropBE[i].size()<<") @"<<tt<<"\n";
#endif //VERBOSE
//		  dropcount_class[5]++;
//Now (09/09/2003) there are only 5
		  dropcount_class[4]++;
		  dropcount++;
		} 
		
		if(jdrop<NBUFS+1) {//found a droppable buffer address
		  //buffer[i][jdrop][3]=-1; //buffer is not occupied	    
		  int dest=buffer[i][jdrop][2];
	    
#ifdef VVERBOSE
//		  cout << "\n\t\tPacket "<<i<<":"<<buffer[i][jdrop][4]<<":"<<jdrop<<" ("<<dropcount_class[5]<<") dropped from buffer "<<jdrop<<" @"<<tt<<"\n";  
		  cout << "\n\t\tPacket "<<i<<":"<<buffer[i][jdrop][4]<<":"<<jdrop<<" ("<<dropcount_class[4]<<") dropped from buffer "<<jdrop<<" @"<<tt<<"\n";  
#endif //VVERBOSE
#ifdef RECIRC
		  /* to recirculate the packets */	    
		  rpacketlength=buffer[i][jdrop][1]; 
		  //rgapwidth=tt-prev_tt[dest]-buffer[i][jdrop][1]; //time between this packet and previous - length of this packet
		  rgapwidth=gap; // gap width of the packet that will take the buffer. Alternatively, we could use the MINGW. Both are "wrong", but what is right?
//	  rpackets[i][0].push(rpacketlength);
//		  rpackets[i][1].push(rgapwidth);
		  rpackets[dest][0].push(rpacketlength);
		  rpackets[dest][1].push(rgapwidth);
#endif // RECIRC
		  
		  int droppedpacketclass=buffer[i][jdrop][4];
		  //if not BE, remove packet from queues (BE does not have these)
		  if(droppedpacketclass<50) {
		    //1. decrement the priority counter 
		    int droppedpacketclasstype=(droppedpacketclass - droppedpacketclass % 10)/10;//0..5
#ifdef PRIORITISE
		    for(int classi=0;classi<=4;classi++) {
		      if(classi+1>droppedpacketclasstype) {
			priority_EF_AF[i][classi]--;
		      }
		    }
#endif // PRIORITISE
		    //2. remove packet from queues for order
		    deque<short int>::iterator dqi;
		    for (dqi = keep_order_EF_AF[i][dest][droppedpacketclasstype].begin(); dqi != keep_order_EF_AF[i][dest][droppedpacketclasstype].end(); dqi++) {
		      if(*dqi==jdrop) {
			keep_order_EF_AF[i][dest][droppedpacketclasstype].erase(dqi);
			break;
		      }
		    }		      
		  } // if not BE
		} // if a packet can be dropped from the buffer
	      } // all buffers full	
	    } // not BE traffic
	    //----------------------------------------------------------------------
	    //    End of pre-emptive drop part
	    //----------------------------------------------------------------------

#ifdef FIFO
	    if(!empty_buffers[i].empty()||jdrop<NBUFS+1) {
	      int j=(jdrop==NBUFS+1)?empty_buffers[i].front():jdrop;
	      if(jdrop==NBUFS+1) {
	      empty_buffers[i].pop(); // remove from FIFO
	      }
#else // not FIFO
	      if (index_empty[i]<NBUFS||jdrop<NBUFS+1) { // if NBUFS means all buffers full 
		// determine the address of the empty buffer
		int j=(jdrop==NBUFS+1)?empty_buffers[i][index_empty[i]]:jdrop;
	      if(jdrop==NBUFS+1) {
		index_empty[i]++;// shift one down, go to next empty buffer
	      } 
#endif // FIFO
#endif DIFFSERV
#else // not DIFFSERV &&  PREEMPTIVE_DROP
	     
#ifdef FIFO
	    if(!empty_buffers[i].empty()) {
	      int j=empty_buffers[i].front();
	      empty_buffers[i].pop(); // remove from FIFO
#else
	      if (index_empty[i]<NBUFS) { // if NBUFS means all buffers full 
		// determine the address of the empty buffer
#ifdef DIFFSERV
		      if(dropped[i]>0) {
//cout<<"DROPTRAIN["<<i<<"]:"<<dropped[i]<<endl;
//			      cout<<dropped[i]<<endl;
			      dropped[i]=0;
		      }
#endif // DIFFSERV
		int j=empty_buffers[i][index_empty[i]];
		index_empty[i]++;// shift one down, go to next empty buffer
#endif // FIFO
#endif // PREEMPTIVE_DROP

	
#ifdef HISTS
#ifdef F
		if(packetcount>WARMUP) {
		  cout  <<"F"<<i<<"\t"<< tt<<"\t"<<index_empty[i]<<"\n";
		}
#endif //F
#endif // HISTS
		
#if BUFTYPE == 0
		int plength=length+MINBGW; // Buffer adapts to packet length
#endif // BUFTYPE 0
		
		// fill the buffer
		buffer[i][j][0]=tt+plength; // time of exit request
		buffer[i][j][1]=length; // length
		buffer[i][j][2]=dest; // destination
		buffer[i][j][3]=0; // can_go? -1=empty;0=in loop; tt=going out 
#ifdef DIFFSERV	
		//----------------------------------------------------------------------
		//    DiffServ additions
		//----------------------------------------------------------------------
		buffer[i][j][4]=packetclass;

		int packetclasstype=(packetclass - packetclass % 10)/10;//0..5
		//1. increment the priority counter 
		/*
		  If packetclasstype is 5 (BE, packetclass 50),
		  then priority_EF_AF[i][4] is checked. This indicates the presence of
		  any packet with class > 50
		  if(packetclasstype>0){
		  if(priority_EF_AF[i][packetclasstype-1]>0){
		  //exit denied
		  }
		  }
		*/	  
		//1. add packet to the "drop" queues
		if(packetclass==50){
		  dropBE[i].push_back(j); // we push the buffer number onto the stack
#ifdef VERBOSE
		  cout <<"Pushed "<<j<<" onto dropBE["<<i<<"] ("<<dropBE[i].size()<<") @"<<tt<<"\n";
#endif //VERBOSE
		} else {
		  if(packetclass>0){ // EF packets are not to be dropped
		    int afj=packetclass % 10;//0..
		    int afi=(packetclass - afj )/10;
		    afj--;
		    afi--;
		    dropAF[i][afi][afj].push_back(j);  
		  }
#ifdef PRIORITISE
		  //2. increment the priority counter
		  for(int classi=0;classi<=4;classi++) {
		    if(packetclasstype<classi+1) {
		      priority_EF_AF[i][classi]++;
		    }
		  }
#endif // PRIORITISE
		  //3. add packet to queues for order
		  keep_order_EF_AF[i][dest][packetclasstype].push_back(j);
		}
		//----------------------------------------------------------------------
#endif // DIFFSERV

#if KEEP_ORDER == 1
		// to conserve packet order
		buffer_stack[i][dest].push(j);
#endif // KEEP_ORDER 1
		
#ifdef VVERBOSE
		cout << j<<" ("<<packetcount<<")\n";
#endif // VVERBOSE
	  
#ifdef HISTS       
		time_in[i][j]=tt;
#endif // 	  
		
#ifdef EQUALISE
		//If buffer nearly full, ask all others to wait
		if (index_empty[i] > NEARLY_FULL) { // panic!
		  please_wait[i]=0;
		  for(int ii=0;ii<NPORTS;ii++) {
		    (ii!=i) && (please_wait[ii]=1);
		  }
		}
#endif // EQUALISE
	  
	      } else {
#ifdef DIFFSERV
dropped[i]++;
//cout<<dropped[i]<<endl;
#endif // DIFFSERV
		// Buffer is full
		//Discard if in warm-up
		if(packetcount>WARMUP) {
#ifdef DIFFSERV
//0,1,2,3,4,5
		  int packetclasstype=(packetclass-(packetclass % 10))/10;
//we need: 0, 1,2,3, 4
//packetclass % 10 gives 0, 0,1,2, 0

switch ( packetclass )
    {
      case 50:
	      dropcount_class[4]++;
        break;
      default:
	      int losslevel=packetclass % 10;
	      dropcount_class[losslevel]++;
    }
//		  dropcount_class[packetclasstype]++;		  
/*
Number of drops in a row:
on every arrival of a packet, set a flagg dropped[i]
*/
		  dropcount++;		  
#ifdef VERBOSE
		  cout << "\tBuffer ["<<i<<"] is full, drop class-"<<packetclasstype<<" packet "<<packetcount<<" ("<<dropcount_class[packetclasstype]<<")\n";
#endif // VERBOSE
#else
		  dropcount++;
#ifdef VERBOSE
		  cout << "\tBuffer ["<<i<<"] is full, drop "<<packetcount<<" ("<<dropcount<<")\n";
#endif // VERBOSE
#endif // DIFFSERV
#ifdef RECIRC
		  /* We must recirculate the dropped packets as well.*/
		  rpacketlength=length;
		  rgapwidth=wait[i]-tt-length;
		  rpackets[i][0].push(rpacketlength);
		  rpackets[i][1].push(rgapwidth);
#endif // RECIRC
		} // if not in warmup
	      } // buffer full
	      // endif: if not ONLY_TRAFFIC
#endif //
	    } //  if (tt>wait[i]), i.e. when a packet arrives 
	    
#ifdef NEW_TIMING
	    // ============================== New timing scheme =========================
	    if((wait[i]>tt)&&(tt_next>wait[i])) {
	      tt_next=wait[i];
	    }
	    // ============================== End ==============================
#endif //  NEW_TIMING
	    
	    ////// END OF PACKET CREATE/STORE/DROP SECTION ////////
	    
#ifndef ONLY_TRAFFIC
	    //---------------------------------------------------------------------------
	    // Check port status
	    //---------------------------------------------------------------------------
/*
	    for(int nport=0;nport<NPORTS;nport++) {
*/
	    for(int nport=0;nport<NDESTS;nport++) {
	      if(portfree[nport]!=1 && portfree[nport] == tt)  { // port was occupied, can now be freed
		portfree[nport]=1; 
#ifdef VVERBOSE
		cout << "\t\tPort "<<nport<<" free @"<<tt<<"\n";
#endif //VVERBOSE
	      }
#ifdef NEW_TIMING
	      //============================== New timing scheme ========================
	      if((portfree[nport]>tt)&&(portfree[nport]<tt_next)) {
		tt_next=portfree[nport];
	      }
	      //============================== End ==============================
#endif // NEW_TIMING
	    }
	    
	    //---------------------------------------------------------------------------
	    // Check all buffers and decide what to do
	    //---------------------------------------------------------------------------
#ifdef ONLY_FILLED
#ifdef FIFO
	    int nfilled=NBUFS-empty_buffers[i].size();
#else
	    int nfilled=index_empty[i];
#endif // FIFO
	    int found_filled=0;
	    int j=0;
	    while(found_filled<nfilled) {
#else
	      for(int j=0;j<NBUFS;j++) {// loop over all buffers
#endif // ONLY_FILLED
		if(buffer[i][j][3]!=-1) { // if the buffer is occupied
#ifdef ONLY_FILLED
		  found_filled++;
#endif // ONLY_FILLED

#if BUFTYPE == 0
		  int plength=buffer[i][j][1]+MINBGW; // Buffer adapts to packet length
#endif // BUFTYPE 0
		  
		  if (buffer[i][j][3]==tt) { // if packet has left buffer (can_go)
		    //clean up:
		    buffer[i][j][3]=-1; //buffer is not occupied
#ifdef FIFO
		    empty_buffers[i].push(j);
#else
		    index_empty[i]--; // another free buffer
		    empty_buffers[i][index_empty[i]]=j; // address of free buffer
#endif // FIFO
		    int dest=buffer[i][j][2];
		    
#ifdef HISTS   
#ifdef F   
		    if(packetcount>WARMUP) {    
		      cout <<"F"<<i<<"\t"<< tt<<"\t"<<index_empty[i]<<"\n";
		    }
#endif //F
#endif // HISTS
	    
#if KEEP_ORDER == 1
		    buffer_stack[i][dest].pop(); // remove buffer address from list
#endif // KEEP_ORDER 1 

#ifdef DIFFSERV  
		    //-------------------------------------------------------------------
		    //    DiffServ cleanup
		    //-------------------------------------------------------------------
		    int packetclass=buffer[i][j][4];
		    //if not BE, remove packet from queues (BE does not have these)
		    if(packetclass<50) { // not BE
		      //1. remove packet from drop queue
		      if(packetclass>0){ // EF packets don't have a drop queue
			int afj=packetclass % 10;//1..3
			int afi=(packetclass - afj )/10;//1..4
			afj--;//0..2
			afi--;//0..3
			deque<short int>::iterator dqi;
			for (dqi = dropAF[i][afi][afj].begin(); dqi != dropAF[i][afi][afj].end(); dqi++) {
			if( *dqi==j) {
		      dropAF[i][afi][afj].erase(dqi);
#ifdef VERBOSE
cout <<"\nPacket Left. Popped "<<j<<" off dropBE["<<i<<"] ("<<dropAF[i][afi][afj].size()<<") @"<<tt<<"\n";
#endif //VERBOSE
		      break;
			}
		      }
		      }

		      int packetclasstype=(packetclass - packetclass % 10)/10;//0..5
#ifdef PRIORITISE
		      //2. decrement the priority counter 
		      for(int classi=0;classi<=4;classi++) {
			if(classi+1>packetclasstype) {
			  priority_EF_AF[i][classi]--;
			}
		      }
#endif // PRIORITISE
		      //3. remove packet to queues for order
		      keep_order_EF_AF[i][dest][packetclasstype].pop_front();
		    } else {// if BE
		      //just remove packet from drop queue
		      deque<short int>::iterator dqi;
		      for (dqi = dropBE[i].begin(); dqi != dropBE[i].end(); dqi++) {
			if( *dqi==j) {
		      dropBE[i].erase(dqi);
#ifdef VERBOSE
		      cout <<"\nPacket Left. Popped "<<j<<" off dropBE["<<i<<"] ("<<dropBE[i].size()<<") @"<<tt<<"\n";
#endif //VERBOSE
		      break;
			}
		      }


		    }
		    //-------------------------------------------------------------------
#endif // DIFFSERV
		    spacketcount++;
		    
#ifdef VVERBOSE
		    cout << "\t\tPacket "<<i<<":"<<buffer[i][j][0]<<":"<<j<<" ("<<spacketcount<<") left buffer "<<j<<" to port "<<dest<<" @"<<tt<<"\n";  
#endif //VVERBOSE
#ifdef RECIRC
		    /* to recirculate the packets */	    
		    rpacketlength=buffer[i][j][1]; 
		    rgapwidth=tt-prev_tt[dest]-buffer[i][j][1]; //time between this packet and previous - length of this packet
//		    rpackets[i][0].push(rpacketlength);
//		    rpackets[i][1].push(rgapwidth);
		    rpackets[dest][0].push(rpacketlength);
		    rpackets[dest][1].push(rgapwidth);
#endif // RECIRC
#ifdef HISTS      
#ifdef A   
		    if(packetcount>WARMUP) {
		      cout <<"A"<< dest<<"\t"<<tt<<"\t"<<tt-prev_tt[dest]-buffer[i][j][1]<<endl;
		    }
#endif //A
#ifdef S   
		    if(packetcount>WARMUP) {
		      //Sojourn time divided by buffer length
		      cout <<"S"<<i<<"\t"<<j<<"\t"<<(tt-time_in[i][j])/BUFL<<"\n";
		      //Latency in ns
		      cout <<"S"<<i<<"\t"<<j<<"\t"<<(tt-time_in[i][j])/100<<"\n";
		    }
#endif //S
#endif // HISTS

		    prev_tt[dest]=tt;
		  } else { // packet is still in the buffer (no can go)
		    if(buffer[i][j][3]==0) { // packet is not leaving the buffer
		      if(tt==buffer[i][j][0]) { // packet arrives at exit point, time to check
			buffer[i][j][0]+=plength; // next iteration
			
#if DEFLECTION == 0
			int dest=buffer[i][j][2];
			// if DEFLECTION == 1, KEEP_ORDER == 0 (no use to keep order)
#if KEEP_ORDER == 1
			// to conserve packet order:
			// only if the buffer address is the first address in the FIFO
			if(buffer_stack[i][dest].front()==j) {
#endif // KEEP_ORDER 1
			  
#ifdef DIFFSERV
			  //-------------------------------------------------------------
			  //   DiffServ priority and order checks
			  //-------------------------------------------------------------

			  int packetclass=buffer[i][j][4];
			  int packetclasstype=(packetclass-(packetclass % 10))/10;
			  //1. Priority
			  /*
			    WV07071003:
			    This prioritisation scheme is not good:
			    1. It leads to high drops and high latency for BE, while not necessarily reducing latency on EF/AF
			    2. It does not prioritise over all inports.
			    Better approach?
			    -We might change the number of exits based on the class. 
			    -We should consider priority over all inports. But this will make matters. 
			    BUT:
			    The reason for prioritisation is to guarantee low latency. Suppose a packet stays in the buffer for 50us, and this for 10 hops, this means 0.5ms delay. But 10 hops@100km/link and 200km/ms means 10* 0.5ms=5ms, so the latency due to the buffers is in the very worst case 10%. In practice, it will rarely be more than 0.1%.
			    =>So we don't need to prioritise!
			  */
#ifdef PRIORITISE
			  if((packetclass<=50) ||(priority_EF_AF[i][packetclasstype-1]==0)) {
#endif // PRIORITISE
			    //no higher-priority packets present, can go
			    //2. Order		    
			    if((packetclass==50)||(keep_order_EF_AF[i][dest][packetclasstype].front()==j)) {
			      //---------------------------------------------------------
			      // End of DiffServ checks
			      //---------------------------------------------------------
#endif // DIFFSERV
			      
#ifdef EQUALISE
			      // See if we were asked to wait and can afford it
			      if ((please_wait[i]!=1) || (index_empty[i]>TOO_FULL)) {
				please_wait[i]=0;
				// Don't wait, send packet anyway
#endif // EQUALISE
				if(portfree[dest] == 1)  { // if the destination port is free 
				  
				  portfree[dest]=tt+buffer[i][j][1]+MINGW; // occupy the port
				  buffer[i][j][3]=tt+buffer[i][j][1]; // set time at which packet will have left buffer
				} // if dest port free
#ifdef EQUALISE
			      } 
#endif // EQUALISE
#else 
			      /* 
				 Deflection routing:
				 Any free port is ok.
				 So loop through all ports, get first free one.
				 But his give disastrous results!
			      */			      
			      int pdest=buffer[i][j][2];
			      if(portfree[pdest]==1) {
				portfree[pdest]=tt+buffer[i][j][1]+MINGW; // port is now occupied
				buffer[i][j][3]=tt+buffer[i][j][1];

#ifdef VVERBOSE
				cout << "\tPacket "<<i<<":"<<buffer[i][j][0]<<":"<<j<<"["<<buffer[i][j][1]<<"] found free port at " << pdest <<" (orig dest was "<< buffer[i][j][2] <<") @"<<tt<<",out @"<<tt+buffer[i][j][1]+MINGW<<"\n";
#endif // VVERBOSE
				
			      } else {//here do some deflection. This is where it goes wrong!
				/* PURE DEFLECTION 
				   if(index_empty[i]==NBUFS-NEARLY_FULL+1) { //NBUFS+1 means never!
				   PURE DEFLECTION */
				int firstfree=-1;				
				// determine first free port
				for(int porti=0;porti<NPORTS;porti++) {
				  if((firstfree==-1) && (portfree[porti]==1)) {
				    firstfree=porti;
				  }
				}		 
				// check if really free. Don't trust C++ :-)
				if((firstfree>-1)&&(portfree[firstfree]==1)) {
#ifdef VVERBOSE
				  cout << "\tPacket "<<i<<":"<<buffer[i][j][0]<<":"<<j<<"["<<buffer[i][j][1]<<"] found free port at " << firstfree <<" (orig dest was "<< buffer[i][j][2] <<") @"<<tt<<",out @"<<tt+buffer[i][j][1]+MINGW<<"\n";
#endif // VVERBOSE
				  
				  portfree[firstfree]=tt+buffer[i][j][1]+MINGW; // port is now occupied
				  buffer[i][j][3]=tt+buffer[i][j][1];			
				  buffer[i][j][2]=firstfree; // of course, this means the original destination is lost. We need an extra field for this, i.e. the label field.
				} // if any port free
				/* PURE DELECTION
				   } //if buffer nearly full
				   PURE DEFLECTION */
			      } //if dest port not free, and buffer nearly full, try deflection
#endif // DEFLECTION 1 

#if DEFLECTION == 0 
#if KEEP_ORDER == 1
			      // if buffer is first in row
			    } 
#endif // KEEP_ORDER 1
#ifdef DIFFSERV
			  } // if first in row
#ifdef PRIORITISE
			} // if highest priority
#endif // PRIORITISE
#endif // DIFFSERV
#endif // DEFLECTION 0 
		      } // if time to check   
		    } // packet is not leaving the buffer
		  } // no can go
#ifdef NEW_TIMING
	  //============================ New timing scheme ==============================
		  long long tt_req=buffer[i][j][0];//+plength;
		  if((tt_req>tt)&&(tt_next>tt_req)) {
		    tt_next=tt_req;
		  }
		  long long tt_out = buffer[i][j][3];
		  if((tt_out>0)&&(tt_next>tt_out)){
		    tt_next=tt_out;
		  }
		  // ============================== End ==============================
#endif // NEW_TIMING   	  
		} // if the buffer is occupied
#ifdef ONLY_FILLED
		j++;
#endif // ONLY_FILLED
	      } // loop over all buffers [j]
#endif // ONLY_TRAFFIC   
	    } //for each port [i]
#ifdef NEW_TIMING
	    // ============================== New timing scheme =========================
	    tt=tt_next;
	    // ============================== End ==============================
#else
	    tt++;
#endif // NEW_TIMING
	  } //while
	  
	  //=============================================================================
	  time(&stoptime);
#ifdef VERBOSE
	  cout <<  "Packets generated: " << packetcount << endl;
	  cout <<  "Packets switched: " << spacketcount << endl;
#ifndef DIFFSERV
	  cout <<  "Packets dropped: " << dropcount << endl;
#else
	  cout <<  "Packets dropped:\n";
//	  for (short int classi=0;classi<=5;classi++) {
	  for (short int classi=0;classi<=4;classi++) {
	    cout <<  "Class "<<classi<<": " << dropcount_class[classi] << endl;
	  }
#endif // DIFFSERV
	  cout <<  "Elapsed time: "<<stoptime-starttime<< endl;
#else
#ifdef HISTS
	  cerr << NBUFS<<"\t"<<packetcount <<"\t"<<spacketcount<<"\t"<<dropcount <<"\n";
#endif // HISTS
#ifndef DIFFSERV
	  cout << NBUFS<<"\t"<<packetcount <<"\t"<<spacketcount<<"\t"<<dropcount<<"\n";
#else
	  cout << NBUFS<<"\t"<<packetcount <<"\t"<<spacketcount<<"\t"<<dropcount<<"\t";
// for (short int classi=0;classi<=5;classi++) {
   cout << dropcount_class[0]*100/pct_EF<<"\t";
//   cout << (dropcount_class[1]+dropcount_class[2]+dropcount_class[3]+dropcount_class[4])*25/pct_AF<<"\t";
// for backward compatibility
   cout << (dropcount_class[1]+dropcount_class[2]+dropcount_class[3])*25/pct_AF<<"\t";

   cout << dropcount_class[4]*100/(100-pct_EF-4*pct_AF)<<"\t";
   cout << dropcount_class[1]*2500/(pct_AF*pct_AF_LO)<<"\t";
   cout << dropcount_class[2]*2500/(pct_AF*(100-pct_AF_HI-pct_AF_LO))<<"\t";
   cout << dropcount_class[3]*2500/(pct_AF*pct_AF_HI);

//   cout << dropcount_class[5]*100/(100-pct_EF-4*pct_AF)<<"\t";

//	  }
   cout << "\n";
#endif //DIFFSERV
	  for (int i=0;i<NPORTS;i++) {
#ifdef FIFO
	    //	    cout <<" "<<empty_buffers[i].size();
#else
	    //	    cout <<" "<<index_empty[i];
#endif // FIFO
	  }
//	  cout<<"\tdt:"<<stoptime-starttime<<"\n";
#endif //VERBOSE
	} // END of main()
	//-----------------------------------------------------------------------------

