/*
 * $RCSfile: extrace.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1994,1994  Arizona Board of Regents
 */

#include "pt.h"

#define DONT_INCLUDE
#include "xkernel.h"
#include "evtrace.h"
#include "simul.h"
#include <math.h>
#include "pktTrace.c"

#define OP_CONNECT		0x1
#define OP_CONNECTED		0x2
#define OP_DONE			0x4
#define OP_LAST			0x8
#define OP_BEGIN		0x10

#define TYPE_FTP		0
#define TYPE_TELNET		1
#define TYPE_SMTP		2
#define TYPE_NNTP		3

#define P(f)			(Pflag ? f : 0)
#define P0(s)			(Pflag ? printf(s) : 0)
#define P1(s,a1)		(Pflag ? printf(s,a1) : 0)
#define P2(s,a1,a2)		(Pflag ? printf(s,a1,a2) : 0)
#define P3(s,a1,a2,a3)		(Pflag ? printf(s,a1,a2,a3) : 0)
#define P4(s,a1,a2,a3,a4)	(Pflag ? printf(s,a1,a2,a3,a4) : 0)
#define P5(s,a1,a2,a3,a4,a5)	(Pflag ? printf(s,a1,a2,a3,a4,a5) : 0)

typedef struct {
  long		time;
  long		runTime;
  long		openTime;
  long		lastTime;
  int		nbufs;
  char		**bufs;
  int		*lens;
  int		protocol;
  int		traceNum;
  TraceEntry	*traces;
} ExTraceStruct;
				 
static int 	debug=0;
/* static int	Protocol=0; */
int		EventA[20000][2], EventN=0, EventFlag=0;
int		newQueue[20000][2], QueueN=1;
int		Lost[10000], LostN=0;
int		InPort0[10000][2], InPort0N=1;
int		InPort1[10000][2], InPort1N=1;				 
int		Busy[1000][2], BusyN=0, HeadStrN=0;
int		PktSndx[10000][2], PktSndy[10000], PktSndN=0, PktBeg[5000];
int		PktLen[5000], PktSndz[10000];
int		TransferDistTp[100], TransferDistCnt[100];
int		DbTransferDistTp[100], DbTransferDistCnt[100];
int		Losses[1000][2], LossesN=0, LossesCnt=0;
int		LossesPkt[1000][2], LossesPktCnt=0;
int             MaxHisto[400], AvgHisto[400], MaxMax=0, MaxAvg=0, Bucket=5;
int             StartTime=10000000;
float           MaxRate=200.0;
float           RateFactor=1.0;
int             ResetTime=-1;
float           queueAvgWidth=0.5;
float           queueAvgGray=1.0;
float           rateAvgWidth=1.5;
float           rateAvgGray=0.0;
char            *RateStr="KB";
/* LSB fix- Use dynamic versus static for Plots! */
PlotStruct	Plots[40], SpecialPlots[20];
EventStruct	Events[20];
int		PlotsN=0, SpecialPlotsN=0, EventsN=0;
char		HeadStr[20][200];
static int	BegTime=0, EndTime=1000000000;
static char	*dbName=NULL, *lenDbName=NULL;
static int	lenDbRead=0, lenDbWrite=0;
static int	Pflag=0, PlotFlag=0;
int             JournalFlag=0, QueueOnlyFlag=0, Top2Flag=0;
int             GroupCnt=1, SaveDataFlag=0;
char            *PlotList=NULL;
static char     *Note=NULL;
static int	Argc;
static char	**Argv;
static char	*HdrTypes[]={"ftp", "telnet", "smtp", "nntp", "????"};

char *malloc();

#ifndef xFree
void xFree(a) char *a; {}
#endif

void xAssertPrint(s, n) char *s; int n; {}

char *myMalloc (len)
  int len;
{
  char *cp;

  if ((cp=malloc(len)) == NULL) {
    fprintf(stderr, "ERROR: Malloc failed for len: %d\n", len);
    exit(1);
  }
  return cp;
}

char *opStr(type)
  int type;
{
  char *cp;
  static char str[100];

  cp = str;
  *cp = '\0';
  if (type & OP_CONNECT)
    strcat(str, "CONNECT ");
  if (type & OP_CONNECTED)
    strcat(str, "CONNECTED ");
  if (type & OP_DONE)
    strcat(str, "DONE ");
  if (type & OP_LAST)
    strcat(str, "LAST ");
  if (type & OP_BEGIN)
    strcat(str, "BEGIN ");
  return str;
}

char *yticF1(iy)

int iy;
{
  double y, z;
  static char buf[1000], *cp=buf, *cpp;

  cpp = cp;
  if (cpp - buf > 900)
    cp = cpp = buf;
  y = ((double) iy)/10.0;
  z = pow(10.0, y);
  if (z < 1000.0) 
    sprintf(cp, "%d", (int)z);
  else if (z < 1000000.0)
    sprintf(cp, "%dK", (int)(z/1000.0 + 0.3));
  else 
    sprintf(cp, "%dM", (int)(z/1000000.0 + 0.3));
  cp += strlen(cp) + 1;
  return cpp;
}

unsigned long getTime(char *cp, int defs)
{
  unsigned long d=0, dc=1, t, s=defs;

  sscanf(cp, "%d", &t);
  while(isdigit(*cp))
    cp++;
  if (*cp == '.')
    while (isdigit(*cp))
      d = d*10 + (*cp++ - '0'), dc *= 10;
  if (*cp == 'm' && *(cp+1) != 'i')
    s = 1000;
  else if (*cp == 'u')
    s = 1;
  else if (*cp == 's')
    s = 1000000;
  else if (*cp == 'm'  &&  *(cp+1) == 'i')
    s = 60000000;
  t = t*s + d*s/dc;
  return t;
}

main (argc, argv)

int  argc;
char *argv[];
{
  char		str[100], *cp, *cp2;
  int		i, j, k, n;
  ExTraceStruct ts;
  FILE		*fin;
  dttracemapentry *trace_map;
  long post_off;
  int post_len;
  dthdr fileHdr;
  long memory=0;
  long totalNum=0;

  Argc = argc;
  Argv = argv;

  pktInit(argc, argv);
  for (k=1; k<argc; k++) {
    if (!strcmp(argv[k], "-d"))
      debug = 1;
    else if (!strcmp(argv[k], "-p"))
      Pflag = 1;
    else if (!strcmp(argv[k], "-plot"))
      PlotFlag = 1;
    else if (!strcmp(argv[k], "-queueonly"))
      QueueOnlyFlag = 1;
    else if (!strcmp(argv[k], "-saveData"))
      SaveDataFlag = 1;
    else if (!strncmp(argv[k], "-journal", 8))
      JournalFlag = 1;
    else if (!strncmp(argv[k], "-queueAvgWidth=", 15))
      sscanf(argv[k]+15, "%f", &queueAvgWidth);
    else if (!strncmp(argv[k], "-queueAvgGray=", 14))
      sscanf(argv[k]+14, "%f", &queueAvgGray);
    else if (!strncmp(argv[k], "-rateAvgWidth=", 14))
      sscanf(argv[k]+14, "%f", &rateAvgWidth);
    else if (!strncmp(argv[k], "-rateAvgGray=", 13))
      sscanf(argv[k]+13, "%f", &rateAvgGray);
    else if (!strncmp(argv[k], "-top2", 5))
      Top2Flag = 1;
    else if (!strncmp(argv[k], "-list=", 6))
      PlotList = argv[k] + 6;
    else if (!strncmp(argv[k], "-group=", 7))
      sscanf(argv[k]+7, "%d", &GroupCnt);
    else if (!strcmp(argv[k], "-header"))
      PlotFlag = 1;
    else if (!strcmp(argv[k], "-tail"))
      PlotFlag = 1;
    else if (!strcmp(argv[k], "-allplot"))
      PlotFlag = 1;
    else if (!strncmp(argv[k], "-bucket=", 8))
      sscanf(argv[k]+8, "%d", &Bucket);
    else if (!strncmp(argv[k], "-start=", 7))
      sscanf(argv[k]+7, "%d", &StartTime);
    else if (!strncmp(argv[k], "-xbeg=", 6)) {
      BegTime = getTime(argv[k]+6, 1000);
      /* sscanf(argv[k]+6, "%d", &BegTime);
      BegTime *= 1000; */
    }
    else if (!strcmp(argv[k], "-n"))
      Note = argv[++k];
    else if (!strncmp(argv[k], "-reset=", 7))
      ResetTime = getTime(argv[k]+7, 1000);
    else if (!strncmp(argv[k], "-maxTime=", 9)) {
      EndTime = getTime(argv[k]+9, 1000000);
      /* sscanf(argv[k]+9, "%d", &EndTime);
      EndTime *= 1000000; */
    }
    else if (!strncmp(argv[k], "-maxRate=", 9)) {
      cp = argv[k] + 9;
      if (!strcmp(cp, "T1")  ||  !strcmp(cp, "t1")) {
        MaxRate = 1536;
        RateFactor = 8.0;
        RateStr = "Kb";
      }
      else if (!strcmp(cp, "T3")  ||  !strcmp(cp, "t3")) {
        MaxRate = 44.210;
        RateFactor = 8.0/1000.0;
      RateStr = "Mb";
      }
      else {
        cp2 = str;
        while ((*cp <= '9'  &&  *cp >= '0') || *cp == '.')
        *cp2++ = *cp++;
        *cp2 = '\0';
        if (*cp == 'm'  ||  *cp == 'M') {
        RateFactor = 8./1000.0;
        RateStr = "Mb";
        }
        sscanf(str, "%f", &MaxRate);
      }
    }
    else if (!strncmp(argv[k], "-db=", 4))
      dbName = argv[k] + 4;
    else if (!strncmp(argv[k], "-lenDb", 6)) {
      cp = argv[k] + 6;
      while (*cp != '=') {
	if (*cp == 'r')
	  lenDbRead = 1;
	else if (*cp == 'w')
	  lenDbWrite = 1;
	cp++;
      }
      lenDbName = cp + 1;
    }
  }

/*  if (!strcmp(argv[argc-1], "-"))
    fin = stdin;
  else */

  if ((fin=fopen(argv[argc-1], "r")) == NULL) {
    fprintf(stderr, "ERROR: Could not open trace file `%s'\n", argv[argc-1]);
    exit(1);
  }

  fread((char *)&fileHdr, sizeof(dthdr), 1, fin);
  post_off = dtPostAmbleLocation(&fileHdr);

  /* go to the postamble location */
  fseek(fin, post_off, 0);

  {
    ExTraceDesc etd;

    fread((char *)&post_len, sizeof(int), 1, fin);
    if ( post_len != sizeof(ExTraceDesc) ) {
        fprintf(stderr,"post_len != sizeof(ExTraceDesc)\n");
        exit(1);
    }
    fread(&etd, sizeof(ExTraceDesc), 1, fin);
    ts.protocol = etd.protocol;
    ts.time     = etd.time;
    ts.runTime  = etd.runTime;
    ts.nbufs    = etd.nbufs;
  }
  /*
  fread((char *)&post_len, sizeof(int), 1, fin);
  fread(&ts.protocol, sizeof(int), 1, fin);
  fread(&ts.time, sizeof(long), 1, fin);
  fread(&ts.runTime, sizeof(long), 1, fin);
  fread(&ts.nbufs, sizeof(int), 1, fin);
  */
  if (debug)
    printf("nbufs: %d\n", ts.nbufs);
  if (ts.nbufs > 0) {
    ts.bufs = (char **) myMalloc(sizeof(char *)*ts.nbufs);
    ts.lens = (int *) myMalloc(sizeof(int)*ts.nbufs);
  }
  else
    ts.bufs = NULL, ts.lens = NULL;
  for (n=0; n<ts.nbufs; n++) {
    fread(&ts.lens[n], sizeof(int), 1, fin);
    if (debug)
      printf("  len for buffer %d: %d\n", n, ts.lens[n]);
    if (ts.lens[n] > 0) {
      ts.bufs[n] = (char *) myMalloc(ts.lens[n]+2);
      fread(ts.bufs[n], 1, ts.lens[n], fin);
    }
  }

  trace_map = dtGetTraceMap(&fileHdr);
  if (! trace_map) {
    printf("Error getting the map of the trace file\n");
    exit(-1);
  }

  for (i=0; i<fileHdr.numberBuffers;i++) {
    ts.traceNum = trace_map[i].size/sizeof(TraceEntry);
    totalNum += trace_map[i].size/sizeof(TraceEntry);
    if (debug)
      printf("Reading %d traces, sizeof trace entry: %d\n", ts.traceNum,
	   sizeof(TraceEntry));
    memory+=(sizeof(TraceEntry)*(ts.traceNum+1));
  }
  ts.traces = (TraceEntry *)myMalloc(memory);
    
  for (i=0;i<fileHdr.numberBuffers;i++) {
    fseek(fin, trace_map[i].seek, 0);
    ts.traceNum = trace_map[i].size/sizeof(TraceEntry);
  fread(ts.traces+sizeof(TraceEntry)*i, sizeof(TraceEntry), ts.traceNum, fin);
  }

  if (fin != stdin)
    fclose(fin);
  
  ts.traceNum = totalNum;
  if (debug)
    printf("traceNum is %d Total memory to be allocated is %ld\n",ts.traceNum,memory);
  ts.openTime = 0;
  for (k=0; k<(20 > ts.traceNum ? ts.traceNum : 20); k++)
    if ((TRACE_GET_EVENT(ts.traces[k]) == TRACE_EVENT_OPEN)) {
      ts.openTime = ts.traces[k].u.time;
      break;
    }
  if (debug)
    printf("openTime: %ld\n", ts.openTime);

  ts.lastTime = 0;
  for (k=ts.traceNum-1; k>=0; k--)
    if ( TRACE_WITH_TIME(ts.traces[k]) ) {
      ts.lastTime = ts.traces[k].u.time;
      break;
    }
  if (debug) {
    printf("lastTime: %ld\n", ts.lastTime);
    printf("time: %ld\n", ts.time);
    printf("runTime: %ld\n", ts.runTime);
  }
  printHeader(&ts);
  printTraces(&ts);
}

char *time2str (t)
  int t;
{
  int 		us, s, m;
  static char	str[100];

  us = t%1000000;
  s = (t/1000000)%60;
  m = t/60000000;
  sprintf(str, "%2d:%02d.%03d %03d", m, s, us/1000, us%1000);
  return str;
}

char *traceStatus (v)
  int v;
{
  static char *status[]={"OK", "ERROR", "BUSY"}, *unknown="unknown";

  if (v < 0  ||  v > 2)
    return unknown;
  else
    return status[v];
}

char *cbType(v)
  int v;
{
  static char *type[]={"NOTBUSY", "SENT"}, *unknown="unknown";

  if (v < OP_NOTBUSY_CB  ||  v > OP_SENT_CB)
    return unknown;
  else
    return type[v-OP_NOTBUSY_CB];
}

char *rvStr(v)
  int v;
{
  static char *rv[]={"FAILED", "SUCCEED"}, *unknown="unknown";

  if (v < RV_FAILED  ||  v > RV_SUCCEED)
    return unknown;
  else
    return rv[v-RV_FAILED];
}

printHeader (ts)
  ExTraceStruct *ts;
{
  printf("Test Date: %s\n\n", ctime((time_t *)&ts->time));
}

#define TIME2STR() 	(timeFlag ? time2str(lastTime) : noTime)
#define DATA		(ts->traces[k].data)
#define LDATA		(ts->traces[k].u.ldata)
#define SDATA1		(ts->traces[k].u.s.sdata1)
#define SDATA2		(ts->traces[k].u.s.sdata2)
#define ID		(ts->traces[k].sid)

#define EVENT(ev)	{EventA[EventN][0]=lastTime;EventA[EventN++][1]=ev; \
			 EventFlag |= ev;}
#define ADD_EVENT(ev,sym,min,max,minmax) {	\
    Events[EventsN].event = ev;			\
    Events[EventsN].symbol = sym;		\
    Events[EventsN].minF = min;			\
    Events[EventsN].maxF = max;			\
    Events[EventsN++].minMaxF = minmax;}

char *TypeNames[5] = {"FTP  ", "TELNT", "SMTP ", "NNTP ", "?????"};

printTraces (ts)
  ExTraceStruct *ts;
{
  char		*cp, str[100];
  int 		i, j, k, ii, lastTime=-1, nextSec=1000000, ev, timeFlag=0;
  int		port, queueLastSize=0, queueLastTime=0, type, id;
  int		timeInc=5000000, timeIncNext=5000000, timeIndex=0;
  int		*queueBusy, *queueNonBusy, queueBusyT=0, queueNonBusyT=0;
  int		queueSizeTimes[200], queueSizeLastTime=0, queueMax=0;
  int		inSum0=0, inSum1=0, inNextTime=100000;
  int		queueLocalMax=0, queueNextTime=50000, queueTimeInc=50000;
  int		dataCnt=0, dataType=0;
  int		lastBytesAttempted=0;
  int		rangekbsSum=0, rangekbsCnt=0;
  int		rangePacketsSent=0, rangeBytesSent=0, rangeLastTime=0;
  int		rangePacketsDrop=0, rangeBytesDrop=0;
  int		totalPacketsSent=0, totalBytesSent=0;
  int		totalPacketsCollision=0, totalBytesCollision=0;
  int		totalPacketsDrop=0, totalBytesDrop=0;
  int		inTotalSumBytes[10], inTotalSumPackets[10];
  char		*dataStr1, *dataStr2, *dataStr3;
  float		x, y;
  static char 	*noTime="             ";
  FILE		*fout=NULL, *fin;

  printf("Number of events: %d\n\n", ts->traceNum);
  for (k=0; k<10; k++)
    inTotalSumBytes[k] = inTotalSumPackets[k] = 0;

  i = ts->lastTime/timeInc + 1;
  queueBusy = (int *)malloc(sizeof(int)*i);
  bzero((char *)queueBusy, sizeof(int)*i);
  queueNonBusy = (int *)malloc(sizeof(int)*i);
  bzero((char *)queueNonBusy, sizeof(int)*i);
  bzero((char *)queueSizeTimes, sizeof(int)*200);

  for (k=0; k<ts->traceNum; k++) {
    if (debug) {
      cp = (char *) &ts->traces[k];
      printf("\nTraceEntry: ");
      for (i=0; i<sizeof(TraceEntry); i++)
	printf("%02x ", cp[i] & 0xff);
      printf("\n");
    }
    if (TRACE_WITH_TIME(ts->traces[k])) {
      lastTime = ts->traces[k].u.time;
      if (lastTime > rangeLastTime  &&  lastTime <= EndTime)
	rangeLastTime = lastTime;
      if (lastTime >= nextSec) {
	nextSec = (lastTime/1000000 + 1)*1000000;
	P(printf(".......... %d sec\n", nextSec/1000000 - 1));
      }
      timeFlag = 1;
      if (ResetTime > 0  &&  lastTime > ResetTime) {
        totalPacketsDrop = 0;
        totalBytesDrop = 0;
        ResetTime = -1;
      }
      if (lastTime > queueNextTime) {
	newQueue[QueueN][0] = queueNextTime-25000;
	newQueue[QueueN++][1] = queueLocalMax;
	queueLocalMax = 0;
	queueNextTime += queueTimeInc;
      }
      if (lastTime > timeIncNext) {
	Losses[LossesN][0] = LossesPkt[LossesN][0] = timeIncNext - timeInc/2;
	Losses[LossesN][1] = LossesCnt/1024;
	LossesPkt[LossesN++][1] = LossesPktCnt;
	LossesCnt = LossesPktCnt = 0;
	ii = timeIncNext - queueLastTime;
	if (queueLastSize > 0) {
	  queueBusy[timeIndex] += ii;
	  queueBusyT += ii;
	}
	else {
	  queueNonBusy[timeIndex] += ii;
	  queueNonBusyT += ii;
	}
	queueLastTime = timeIncNext;
	timeIndex++;
	timeIncNext += timeInc;
      }
    }
    else
      timeFlag = 0;

    dataCnt++;

    /* --- Trace event specific things */
    switch(ev=TRACE_GET_EVENT(ts->traces[k])) {

    case TRACE_EVENT_OPENEN:
      P(printf(" OE  %s OpenEnable: %s\n", TIME2STR(), traceStatus(DATA)));
      break;

    case TRACE_EVENT_OPEN:
      if (ts->protocol == TRACE_PROTL_TRAFFIC) {
	P(printf(" O   %s (%4d) Start %s, ", TIME2STR(), DATA, HdrTypes[ID]));
	type = ID;
	id = DATA;
	k++;
	P(printf("srvr:%2d, ", LDATA));
	k++;
	if (type == TYPE_TELNET) {
	  P(printf("src: %2d, duration: %d.%03d\n", ID, LDATA/1000, 
		   LDATA%1000));
	}
	else {
	  P(printf("src: %2d, nitems: %d, len: %d\n", ID, DATA, LDATA));
	}
	if (type == TYPE_FTP) {
	  EVENT(E_FTP);
	}
	else if (type == TYPE_TELNET) {
	  EVENT(E_TELNET);
	}
	else if (type == TYPE_NNTP) {
	  PktBeg[id] = lastTime;
	  PktLen[id] = LDATA;
	  EVENT(E_NNTP);
	}
	else if (type == TYPE_SMTP) {
	  PktBeg[id] = lastTime;
	  PktLen[id] = LDATA;
	  EVENT(E_SMTP);
	} 
      }
      break;

    case TRACE_EVENT_SEND_BUSY:
      EVENT(E_BUSY);
      if (ts->protocol == TRACE_ROUTER_FCFS || ts->protocol == TRACE_ROUTER_RED)
	P(printf(" sB  %s send BUSY, queue:%d, pkID:%d, outPort:%d\n", 
	       TIME2STR(), DATA, LDATA, ID));
      else
	P(printf(" sB  %s send BUSY, queue:%d\n", TIME2STR(), DATA));
      if (ID == 0) {
	if (DATA > queueLocalMax)
	  queueLocalMax = DATA;
      }
      break;

    case TRACE_EVENT_SEND_OKAY:
      EVENT(E_SEND);
      if (ts->protocol == TRACE_ROUTER_FCFS || ts->protocol == TRACE_ROUTER_RED)
	P(printf(" s?  %s send OKAY, len:%d, pkID:%d, outPort:%d\n", 
	       TIME2STR(), DATA, LDATA, ID));
      else
	P(printf(" s?  %s send OKAY, len:%d\n", TIME2STR(), DATA));
      lastBytesAttempted = DATA;
      break;

    case TRACE_EVENT_SEND:
      if (ts->protocol == TRACE_PROTL_TRAFFIC) {
	P(printf(" S   %s (%4d) %s sending %d bytes\n",
		 TIME2STR(), DATA, HdrTypes[ID], LDATA));
	PktBeg[DATA] = lastTime;
	PktLen[DATA] = LDATA;
      }
      break;

    case TRACE_EVENT_CB:
      P(printf(" cb  %s callback: %s, rv:%s\n", TIME2STR(), cbType(DATA), 
	     rvStr(ID)));
      if (ts->protocol == TRACE_ROUTER_FCFS || ts->protocol == TRACE_ROUTER_RED ) 
	dataCnt=0, dataType=2, dataStr1="outPort", dataStr2="pktID";
	
      if ((DATA == OP_SENT_CB)  &&  (ID == RV_FAILED)) {
	EVENT(E_COLL);
	totalPacketsCollision++;
	totalBytesCollision += lastBytesAttempted; /* BOGUS */
	P(printf("     %s      totalColls:%d, totalBytesInColls:%d\n", 
	       noTime, totalPacketsCollision, totalBytesCollision));
      }
      break;

    case TRACE_EVENT_SENT_OKAY:
      EVENT(E_SENT);
      P(printf(" s   %s sent OKAY, len:%d, queue:%d\n", TIME2STR(), DATA,
	     LDATA));
      if (port == 0) {
	if (LDATA > queueLocalMax)
	  queueLocalMax = LDATA;
      }
      totalPacketsSent++;
      if (lastTime >= BegTime  &&  lastTime <= EndTime)
	rangeBytesSent += DATA, rangePacketsSent++;
      totalBytesSent += DATA;
      P(printf("     %s      totalPackets:%d, totalBytes:%d\n", noTime,
	     totalPacketsSent, totalBytesSent));
      dataCnt=0, dataType=2, dataStr1="retry count", dataStr2="retry delay";
      break;

    case TRACE_EVENT_DATA:
      P(printf("     %s ", TIME2STR()));
      if (dataCnt == 1) {
	if (dataType == 1)
	  P(printf("%s:%d\n", dataStr1, LDATA));
	else if (dataType == 2)
	  P(printf("%s:%d, %s:%d\n", dataStr1, DATA, dataStr2, LDATA));
	else if (dataType == 3)
	  P(printf("%s:%d, %s:%d, %s:%d\n", dataStr1, DATA, dataStr2, SDATA1,
		 dataStr3, SDATA2));
	else
	  P(printf("\n"));
	if (!strcmp("outPort", dataStr1))
	  port = DATA;
	else if (!strcmp("outPort", dataStr2))
	  port = LDATA;
      }
      else
	P(printf("DATA: %d, %d\n", DATA, LDATA));
      break;

    case TRACE_EVENT_DROP:
      EVENT(E_DROP);
      if (ts->protocol == TRACE_ROUTER_FCFS  || ts->protocol == TRACE_ROUTER_RED)
	P(printf(" d   %s dropping, len:%d, queue:%d, outPort:%d\n", 
	       TIME2STR(), DATA, LDATA, ID));
      else
	P(printf(" d   %s dropping, len:%d, queue:%d\n", TIME2STR(), DATA,
	       LDATA));
      if (ID == 0) {
	if (LDATA > queueLocalMax)
	  queueLocalMax = LDATA;
      }
      Lost[LostN++] = lastTime;
      totalPacketsDrop++;
      totalBytesDrop += DATA;
      if (lastTime >= BegTime  &&  lastTime <= EndTime)
	rangeBytesDrop += DATA, rangePacketsDrop++;
      LossesPktCnt++;
      LossesCnt += DATA;
      P(printf("     %s      totalPacketsDropped:%d, totalBytesDroped:%d\n", 
	     noTime, totalPacketsDrop, totalBytesDrop));
      break;

    case TRACE_EVENT_BACKOFF:
      EVENT(E_BACKOFF);
      P(printf(" bo  %s backing off:%d, queue:%d\n", TIME2STR(), DATA, LDATA));
      dataCnt=0, dataType=2, dataStr1="retry count", dataStr2="retry delay";
      /* DO MACRO FOR ABOVE */
      break;

/*     case TRACE_EVENT_PUSH_DROP: */
/*       printf(" Pd  %s Push DROP, len:%d\n", TIME2STR(), DATA); */
/*       totalPacketsDrop++; */
/*       totalBytesDrop += DATA; */
/*       printf("     %s      totalPacketsDropped:%d, totalBytesDroped:%d\n",  */
/* 	     noTime, totalPacketsDrop, totalBytesDrop); */
/*       break; */

    case TRACE_EVENT_QUEUE:
      if (TRACE_WITH_TIME(ts->traces[k])) {
	P(printf("     %s queue:%d, port:%d\n", TIME2STR(), DATA, ID));
	if (ID == 0) {
	  if (DATA > queueLocalMax)
	    queueLocalMax = DATA;
	  if (DATA > queueMax)
	    queueMax = DATA;
	  if (queueLastSize != DATA) {
	    queueSizeTimes[queueLastSize] += (lastTime - queueSizeLastTime);
	    queueSizeLastTime = lastTime;
	  }
	  if (queueLastSize == 0  &&  DATA > 0) {
	    queueNonBusy[timeIndex] += (lastTime - queueLastTime);
	    queueNonBusyT += (lastTime - queueLastTime);
	    queueLastTime = lastTime;
/* 	    queueLastSize = DATA; */
	  }
	  else if (queueLastSize > 0  &&  DATA == 0) {
	    queueBusy[timeIndex] += (lastTime - queueLastTime);
	    queueBusyT += (lastTime - queueLastTime);
	    queueLastTime = lastTime;
/* 	    queueLastSize = DATA; */
	  }
	  queueLastSize = DATA;
	}
      }
      else {
	P(printf("     %s queue:%d, port:%d\n", TIME2STR(), LDATA, DATA));
	if (DATA == 0) {
	  if (LDATA > queueLocalMax)
	    queueLocalMax = LDATA;
	}
      }
      break;

    case TRACE_EVENT_PUSH:
      P(printf(" P   %s Push, len:%d\n", TIME2STR(), DATA));
      break;

    case TRACE_EVENT_IN:
      if (ts->protocol == TRACE_ROUTER_FCFS || ts->protocol == TRACE_ROUTER_RED) {
        int inPort;
	if (lastTime > inNextTime) {
	  if (PlotFlag) {
	    InPort0[InPort0N][0] = inNextTime-50000;
	    InPort0[InPort0N++][1] = (inSum0*10)/1024;
	    InPort1[InPort1N][0] = inNextTime-50000;
	    InPort1[InPort1N++][1] = (inSum1*10)/1024;
	  }
	  inSum0 = inSum1 = 0;
	  inNextTime += 100000;
	}
        inPort = ID & 0x7f;
        inTotalSumBytes[inPort] += DATA;
        inTotalSumPackets[inPort]++;
        if (inPort == 0)
	  inSum0 += DATA;
	else if (inPort == 1) 
	  inSum1 += DATA;
        if ((ID & 0x80) != 0) { /* we have a packet trace! */
          char    s1[20], s2[20];
          u_short sport, dport;
          int     drop=0;

          CurPkt->len = DATA;
          CurPkt->inPort = inPort;
          CurPkt->time = lastTime;
          P(printf(" i   %s in, len:%d, port:%d\n", TIME2STR(), CurPkt->len,
                   inPort));
          k++;
          CurPkt->id.ipSrc = SDATA1;
          CurPkt->id.ipDst = SDATA2;
          CurPkt->outPort = ID;
          CurPkt->prot = DATA;
          P(printf("                   src:%03d.%03d dst:%03d.%03d prot:%3doutPort:%d\n",
                   CurPkt->id.ipSrc>>8, CurPkt->id.ipSrc&0xff,
                   CurPkt->id.ipDst>>8,
                   CurPkt->id.ipDst&0xff, CurPkt->prot, CurPkt->outPort));
          if (CurPkt->prot == 201) {
            k++;
            CurPkt->queueCnt = DATA;
            while (PktLenArraySize > CurPkt->queueCnt) {
              PktQueueLen -= PktLenArray[PktLenArrayBeg];
              PktLenArrayBeg = (PktLenArrayBeg + 1) & (PKT_LEN_ARRAY - 1);
              PktLenArraySize--;
	    }
            if (CurPkt->queueCnt < PktQueueDropCntArg) {
              PktLenArray[PktLenArrayEnd] = CurPkt->len;
              PktLenArrayEnd = (PktLenArrayEnd + 1) & (PKT_LEN_ARRAY - 1);
              PktQueueLen += CurPkt->len;
              if (PktLenArraySize == CurPkt->queueCnt)
                CurPkt->queueLen = PktQueueLen;
              else
                CurPkt->queueLen = 0;
              PktLenArraySize++;
            }
            else
              drop = 1;

            CurPkt->id.sport = sport = SDATA1;
            CurPkt->type = 4;
            if (sport >= 3007  &&  sport <= 3010) {
              strcpy(s1, TypeNames[sport-3007]);
              CurPkt->type = sport-3007;
            }
            else
              sprintf(s1, "%5d", sport);
            CurPkt->id.dport = dport = SDATA2;
            if (dport >= 3007  &&  dport <= 3010) {
              strcpy(s2, TypeNames[dport-3007]);
              CurPkt->type = 5 + dport-3007;
            }
            else
              sprintf(s2, "%5d", dport);
            CurPkt->flags = ID;
            str[0] = '\0';
            if (CurPkt->flags & 0x01) strcat(str, "FIN ");
	    if (CurPkt->flags & 0x02) strcat(str, "SYN ");
	    if (CurPkt->flags & 0x04) strcat(str, "RST ");
            if (CurPkt->flags & 0x08) strcat(str, "PUSH ");
            if (CurPkt->flags & 0x10) strcat(str, "ACK ");
            if (CurPkt->flags & 0x20) strcat(str, "URG ");
            if (CurPkt->flags & 0x40) strcat(str, "SS ");
            if (CurPkt->flags & 0x80) strcat(str, "SA ");
            P(printf("                   q:%3d, sport:%s, dport:%s, flags:%s\n",
                     CurPkt->queueCnt, s1, s2, str));

            if (!drop)
              pktTrace(lastTime);
/*
            if (tcpPktsTimeBeg < 0) {
              tcpPktsTimeBeg = lastTime;
              tcpPktsTimeEnd = lastTime + tcpPktsTimeLen*1000;
              tcpPktsTimeNext = lastTime + tcpPktsTimeInc;
              for (k=0; k<4; k++) {
                tcpPktsCntArray[k] = (int (*)[2])
                    malloc(sizeof(int)*(2*tcpPktsTimeLen/tcpPktsTimeInc+12));
                tcpPktsCntZarray[k] = (int *)
                    malloc(sizeof(int)*(tcpPktsTimeLen/tcpPktsTimeInc+12));
                tcpPktsLenArray[k] = (int (*)[2])
                    malloc(sizeof(int)*(2*tcpPktsTimeLen/tcpPktsTimeInc+12));
                tcpPktsLenZarray[k] = (int *)
                    malloc(sizeof(int)*(tcpPktsTimeLen/tcpPktsTimeInc+12));
              }
              tcpPktsSsArray[k] = (int (*)[2])
                  malloc(sizeof(int)*(2*tcpPktsTimeLen/tcpPktsTimeInc+12));
              tcpPktsSsZarray[k] = (int *)
                  malloc(sizeof(int)*(tcpPktsTimeLen/tcpPktsTimeInc+12));
              tcpPktsSaArray[k] = (int (*)[2])
                  malloc(sizeof(int)*(2*tcpPktsTimeLen/tcpPktsTimeInc+12));
              tcpPktsSaZarray[k] = (int *)
                  malloc(sizeof(int)*(tcpPktsTimeLen/tcpPktsTimeInc+12));
            }
*/
          }
          break;
        }
      }
      P(printf(" i   %s in, len:%d, port:%d\n", TIME2STR(), DATA, ID));
      dataCnt=0, dataType=2, dataStr1="-", dataStr2="pktID";
      break;

    case TRACE_EVENT_PUSH_SEND:
      P(printf(" Ps  %s Push send, len:%d, queue:%d\n", TIME2STR(), DATA, 
	       LDATA));
      if (LDATA > queueLocalMax)
	queueLocalMax = LDATA;
      break;

    case TRACE_EVENT_CLOSE:
      if (ts->protocol == TRACE_PROTL_TRAFFIC) {
	P(printf(" C   %s (%4d) Close conv %s, total bytes sent: %d\n",
		 TIME2STR(), DATA, HdrTypes[ID], LDATA));
      }
      break;

    case TRACE_EVENT_DEMUX:
      if (ts->protocol == TRACE_PROTL_TRAFFIC) {
	P(printf(" D   %s (%4d) Demux %s ", TIME2STR(), DATA, HdrTypes[ID]));
	id = DATA;
	k++;
	if (PktBeg[id] > 0  &&  (DATA & OP_DONE)) {
	  char *str[100];
	  PktSndx[PktSndN][0] = PktBeg[id];
	  PktSndx[PktSndN][1] = lastTime;
	  PktSndy[PktSndN] = ( PktLen[id] / 
			      (1024.0*(lastTime-PktBeg[id])/1000000.0) + 0.5);
	  PktSndz[PktSndN] = log10((double)PktLen[id]+1)*10;
	  if (PktLen[id] < 1000) 
	    ii = PktLen[id]/100;
	  else if (PktLen[id] < 10000)
	    ii = PktLen[id]/1000 + 9;
	  else if (PktLen[id] < 100000)
	    ii = PktLen[id]/10000 + 18;
	  else if (PktLen[id] < 1000000)
	    ii = PktLen[id]/100000 + 27;
	  else
	    ii = 37;
	  TransferDistTp[ii] += PktSndy[PktSndN];
	  TransferDistCnt[ii]++;
	  PktSndN++;
/* 	  if (!Pflag) { */
/* 	    strcpy(str, time2str(PktBeg[id])); */
/* 	    printf("%s  %s - %d\n", str, time2str(lastTime), */
/* 		   PktSndy[PktSndN-1]); */
/* 	  } */
	  if (PktSndy[PktSndN-1] < 0  ||  PktSndy[PktSndN-1] > 1000) {
	    PktSndN--;
	    if (!Pflag)
	      printf("------\n");
	  }
	  PktBeg[id] = 0;
	}
	if (ID == 0) {
	  P(printf("len: %d, %s  SERVER\n", LDATA, opStr(DATA)));
	}
	else {
	  P(printf("len: %d, %s  CLIENT\n", LDATA, opStr(DATA)));
	}
      }
      else {
	P(printf(" D   %s Demux, len:%d\n", TIME2STR(), DATA));
      }
      break;

    case TRACE_EVENT_ERROR:
      EVENT(E_ERROR);
      P(printf("*E   %s ERROR, d:%d, dl:%d\n", TIME2STR(), DATA, LDATA));
      break;

    case TRACE_EVENT_ERROR_DROP:
      P(printf("*Ed  %s ERROR & DROP, d:%d, dl:%d\n", TIME2STR(), DATA, 
	       LDATA));
      totalPacketsDrop++;
      totalBytesDrop += DATA;
      if (lastTime >= BegTime  &&  lastTime <= EndTime) 
	rangeBytesDrop += DATA, rangePacketsDrop++;
      break;

    case TRACE_EVENT_CTL_PROTL:
      P(printf(" Cp  %s Control Protocol, op:%d\n", TIME2STR(), DATA));
/*       if (DATA == GETMYHOST) */
/* 	printf(" (GETMYHOST)\n"); */
/*       else */
/* 	printf(" ( ? )\n"); */
      break;

    default:
      printf(" ?   %s Unknown event: %d\n", TIME2STR(), ts->traces[k].event);

    }
  }

  Losses[LossesN][0] = LossesPkt[LossesN][0] = timeIncNext - timeInc/2;
  Losses[LossesN][1] = LossesCnt/1024;
  LossesPkt[LossesN++][1] = LossesPktCnt;

  if (ts->protocol == TRACE_PROTL_TRAFFIC) {
    float       x;
    PlotStruct  *psp, *spsp;

    psp = &Plots[PlotsN++];
    psp->zFlag = 2;
    psp->main = 1;
    psp->arrayN = PktSndN;
    psp->array = PktSndx;
    psp->zarray = PktSndy;
    psp->other = NULL;
    strcpy(psp->ytitle, "Transer KB/s");
    sprintf(psp->gtitle, " ");
    sprintf(psp->plotType, "0 0 1 plotWbars\n");
    strcpy(psp->id, "Traffic Transfers");
    psp->yticRound = 1;
    psp->yticSizeInit = 10;
    psp->yticSizeInc = 10;
    psp->yticMaxNum = 10;

    psp = &Plots[PlotsN++];
    psp->zFlag = 2;
    psp->main = 1;
    psp->arrayN = PktSndN;
    psp->array = PktSndx;
    psp->zarray = PktSndz;
    psp->other = NULL;
    strcpy(psp->ytitle, "Transfer size");
    sprintf(psp->gtitle, " ");
    sprintf(psp->plotType, "0 0 1 plotWbars\n");
    strcpy(psp->id, "Traffic Transfers");
    psp->yticRound = 1;
    psp->yticSizeInit = 10;
    psp->yticSizeInc = 10;
    psp->yticMaxNum = 10;
    psp->yticFun = yticF1;

    ADD_EVENT(E_SMTP, P_VBAR, 1.0, 0.0, 0.0);
    ADD_EVENT(E_TELNET, P_VBAR_WCIRCLE, 1.0, 0.0, 0.0);
    ADD_EVENT(E_FTP, P_LVBAR_WCIRCLE, 1.0, 0.0, 0.0);
    ADD_EVENT(E_NNTP, P_VBAR_WDOT, 1.0, 0.0, 0.0);

    if (lenDbName != NULL  &&  lenDbRead) {
      if ((fin=fopen(lenDbName, "r")) == NULL) {
	printf("ERROR: Could not open lenDbName: `%s'\n", lenDbName);
	lenDbName = NULL;
	lenDbRead = lenDbWrite = 0;
      }
      else {
	for (k=0; k<37; k++) {
	  if (fscanf(fin, "%d %f %d", &ii, &x, &DbTransferDistCnt[k]) != 3) {
	    printf("ERROR: didn't read 3 things\n");
	    lenDbName = NULL;
	    lenDbRead = lenDbWrite = 0;
	    break;
	  }
	  DbTransferDistTp[k] = x*DbTransferDistCnt[k];
	}
	fclose(fin);
      }
    }
    if (lenDbName != NULL  &&  lenDbWrite) {
      if ((fout=fopen(lenDbName, "w")) == NULL) {
	printf("ERROR: Could not open lenDbName: `%s'\n", lenDbName);
	lenDbName = NULL;
	lenDbRead = lenDbWrite = 0;
      }
    }
 	    
    for (k=0; k<37; k++) {
      if (k < 10)
	ii = k*100;
      else if (k < 19)
	ii = (k-9)*1000;
      else if (k < 28)
	ii = (k-18)*10000;
      else if (k < 37)
	ii = (k-27)*100000;
      DbTransferDistTp[k] += TransferDistTp[k];
      DbTransferDistCnt[k] += TransferDistCnt[k];
      if (fout == NULL) {
	if (TransferDistCnt[k] != 0)
	  printf("%7d  %5.1f  %d\n", ii, 
		 ((double)TransferDistTp[k])/TransferDistCnt[k], 
		 TransferDistCnt[k]);
	else 
	  printf("%7d  %5.1f  %d\n", ii, 0.0, 0);
      }
      else {
	if (DbTransferDistCnt[k] == 0)
	  fprintf(fout, "%7d  %5.3f  %d\n", ii, 0.0, 0);
	else
	  fprintf(fout, "%7d  %5.3f  %d\n", ii, 
		  ((double)DbTransferDistTp[k])/DbTransferDistCnt[k], 
		  DbTransferDistCnt[k]);
	if (TransferDistCnt[k] != 0)
	  printf("%7d  %5.1f  %d", ii, 
		 ((double)TransferDistTp[k])/TransferDistCnt[k], 
		 TransferDistCnt[k]);
	else
	  printf("%7d  %5.1f  %d", ii, 0.0, 0);
	if (DbTransferDistCnt[k] != 0)
	  printf("     %5.1f  %d\n", 
		 ((double)DbTransferDistTp[k])/DbTransferDistCnt[k], 
		 DbTransferDistCnt[k]);
	else
	  printf("     %5.1f  %d\n", 0.0, 0);
      }
    }
    if (fout != NULL) {
      fclose(fout);
      fout = NULL;
    }
    
    if (ts->nbufs > 0) {
      char *cp;

      cp = ts->bufs[0];
      while (*cp != '\0') {
	strcpy(HeadStr[HeadStrN++], cp);
	cp += strlen(cp) + 1;
      }
    }
  }
  else if (ts->nbufs > 0) {
    char	str[100], dbstr[20];
    int		sum=0, next, inc, totalSum=0, rFlag, t;
    int		qsum=0, qcount=0;
    int         gmin, gmax, gsum, gcnt;
    int         kk;
    float	totalBusy;
    ITrace 	*itp;
    MaxMinTrace *mtp;
    PlotStruct  *psp, *spsp, *psp1, *psp2;

    for (j=0; j<ts->nbufs; j++) {
      rFlag = 0;
      fout = NULL;
      itp = (ITrace *) ts->bufs[j];
      if (itp->stype == TRACE_STRUCT_I) {
        if (itp->arrayNum == 0)
          continue;
        if (dbName != NULL  &&  !strncmp(itp->id, "inout-192", 9))
          fout = fopen(dbName, "a"), strcpy(dbstr, "ri");
        else if (dbName != NULL  &&  !strncmp(itp->id, "out-192", 7))
          fout = fopen(dbName, "a"), strcpy(dbstr, "ro"), rFlag = 1;
        else if (dbName != NULL  &&  !strncmp(itp->id, "out-ethd", 8))
	  fout = fopen(dbName, "a"), strcpy(dbstr, "teo");
	else if (dbName != NULL  &&  !strncmp(itp->id, "out-ethd", 8)) 
	  fout = fopen(dbName, "a"), strcpy(dbstr, "meo");
	else if (dbName != NULL  &&  !strcmp(itp->id, "in-ethd-h1n2")) 
	  fout = fopen(dbName, "a"), strcpy(dbstr, "tei");
	else if (dbName != NULL  &&  !strcmp(itp->id, "in-ethd-h2n2")) 
	  fout = fopen(dbName, "a"), strcpy(dbstr, "mei");

	sum = totalSum = 0;
	printf("\nDoing %s\n", itp->id);
	psp = &Plots[PlotsN++];
	psp->zFlag = 0;
	psp->main = 1;
	psp->arrayN = itp->arrayNum;
	psp->array = (int (*)[2]) malloc(sizeof(int)*(2*itp->arrayNum+2));
	spsp = &Plots[PlotsN++];
	spsp->arrayN = 0;
	spsp->zFlag = 3;
	spsp->main = 0;
	spsp->array = (int (*)[2]) malloc(sizeof(int)*2*100);
	psp1 = &Plots[PlotsN++];
	psp1->zFlag = 3;
	psp1->main = 0;
	psp1->array = Losses;
	psp1->arrayN = LossesN;
	strcpy(psp1->plotType, "0 %f 6 plotNum\n");
	psp1->minF = 1.0;
	psp1->maxF = 0.0;
	psp1->minMaxF = 0.03;
	psp2 = &Plots[PlotsN++];
	psp2->zFlag = 3;
	psp2->main = 0;
	psp2->array = LossesPkt;
	psp2->arrayN = LossesN;
	strcpy(psp2->plotType, "0 %f 6 plotNum\n");
	psp2->minF = 1.0;
	psp2->maxF = 0.0;
	psp2->minMaxF = -0.08;
	next = inc = 5000000/itp->timeInc;
        if (SaveDataFlag) {
          FILE *fout;
          k = ((2*BegTime)/itp->timeInc - 1)/2;
          if ((fout = fopen(itp->id, "w")) != NULL) {
          printf("Saving data in file: %s\n", itp->id);
            fwrite(itp->array + k, sizeof(short), 1024, fout);
            fclose(fout);
          }
          else
            printf("Couldn't open saveData file: %s\n", itp->id);
        }

	for (k=0; k<itp->arrayNum; k++) {
	  psp->array[k][0] = t = (2*k+1)*itp->timeInc/2;
	  psp->array[k][1] = itp->array[k]*RateFactor;
	  if (t >= BegTime  &&  t <= EndTime)
	    rangekbsSum += itp->array[k], rangekbsCnt++;
	  sum += itp->array[k];
	  totalSum += itp->array[k];
	  if (k == next) {
	    spsp->array[spsp->arrayN][0] = 
	      next*itp->timeInc - inc*itp->timeInc/2;
	    spsp->array[spsp->arrayN++][1] = (100*sum) / 
					      (inc*MaxRate/RateFactor);
	    next += inc;
	    sum = 0;
	  }
	}
	if (lastTime < k*itp->timeInc)
	  lastTime = k*itp->timeInc;
        if (sum != 0) {
	  spsp->array[spsp->arrayN][0] = next*itp->timeInc -inc*itp->timeInc/2;
	  spsp->array[spsp->arrayN++][1] = (100*sum)/((k-(next-inc))*
	                                              MaxRate/RateFactor);
        }
	strcpy(spsp->plotType, "0 %f 6 plotNumPercent\n");
	spsp->minF = 0.0;
	spsp->maxF = 1.0;
	spsp->minMaxF = 0.03;
/* 	psp->other = spsp; */
	sprintf(psp->ytitle, "%s/s %s\n", RateStr, itp->id);
	sprintf(psp->gtitle, " ");
/*      if (JournalFlag)
          sprintf(psp->plotType,
                "0.2 0 plotStraightLines\n%.2f %.2f 9 plotNAvgStraightLines\n",
                  rateAvgWidth, rateAvgGray);
        else
*/
          sprintf(psp->plotType,
                  "0 0 plotStraightLines\n%.2f %.2f 9 plotNAvgStraightLines\n",
                  rateAvgWidth, rateAvgGray);
	strcpy(psp->id, itp->id);
	psp->yticRound = 1;
	psp->yticSizeInit = 10;
	psp->yticSizeInc = 10;
	psp->yticMaxNum = 10;
	totalBusy = (100.0*totalSum)/(MaxRate*k/RateFactor);
	printf("Total Busy:    %.1f%%\n", totalBusy);
	printf("Total KB:      %d\n", itp->byteCnt/1024);
	printf("Total Packets: %d\n", itp->packetCnt);
	for (k=0; k<spsp->arrayN; k++) {
	  if (fout != NULL)
	    fprintf(fout, "%s%d: %d\n", dbstr, k, spsp->array[k][1]);
          printf("%3d-%3d Utilization ratio to %.2f%s/s: %3d%%\n", k*5, (k+1)*5,
                 MaxRate, RateStr, spsp->array[k][1]);
	}
	if (fout != NULL && rFlag) {
	  fprintf(fout, "total busy: %.1f\n", totalBusy);
	  fprintf(fout, "KB dropped: %.1f\n", totalBytesDrop/1024.0);
	  fprintf(fout, "pk dropped: %d\n", totalPacketsDrop);
	  fclose(fout);
	  fout = NULL;
	}
	else if (fout != NULL) {
	  fclose(fout);
	  fout = NULL;
	}
	for (k=0; strlen(itp->id)+k<15; k++)
	  str[k] = ' ';
	str[k] = '\0';
	sprintf(HeadStr[HeadStrN++],
	  "%s:%s packets: (%d, %d), KB: (%.1f, %.1f), (%.1f, %.1f) %s/s avg",
		itp->id, str, itp->packetCnt, rangePacketsSent, 
		itp->byteCnt/1024.0, rangeBytesSent/1024.0,
                itp->byteCnt/(1024.0*lastTime/1000000.0/RateFactor),
                ((float)rangekbsSum)/rangekbsCnt/RateFactor, RateStr);
      }
      else if (itp->stype == TRACE_STRUCT_MINMAX) {
	mtp = (MaxMinTrace *)itp;
	if (dbName != NULL  &&  !strcmp(mtp->id, "queue-192.0.2.1"))
	  fout = fopen(dbName, "a"), strcpy(dbstr, "aqs");
	else
	  fout = NULL;
	printf("\nDoing %s\n", mtp->id);
	psp = &Plots[PlotsN++];
	psp->zFlag = 1;
	psp->main = 1;
        psp->arrayN = mtp->arrayNum/GroupCnt;
        psp->array = (int (*)[2]) malloc(sizeof(int)*(2*mtp->arrayNum/GroupCnt+12));
        psp->zarray = (int *) malloc(sizeof(int)*(mtp->arrayNum/GroupCnt+12));
	spsp = &Plots[PlotsN++];
	spsp->arrayN = 0;
	spsp->zFlag = 3;
	spsp->main = 0;
	spsp->array = (int (*)[2]) malloc(sizeof(int)*2*100);
        psp1 = &Plots[PlotsN++];
        psp1->zFlag = 0;
        psp1->main = 0;
        psp1->arrayN = mtp->arrayNum/GroupCnt;
        psp1->array = (int (*)[2]) malloc(sizeof(int)*(2*mtp->arrayNum+2));
	next = inc = 5000000/mtp->timeInc;
	sum = ii = 0;
        gmin = mtp->minArray[0];
        gmax = mtp->maxArray[0];
        gsum = gcnt = kk = 0;

        if (SaveDataFlag) {
          FILE *fout;
          k = ((2*BegTime)/mtp->timeInc - 1)/2;
          if ((fout = fopen(mtp->id, "w")) != NULL) {
            printf("Saving data in file: %s\n", mtp->id);
            fwrite(mtp->maxArray + k, sizeof(char), 1024, fout);
            fclose(fout);
          }
          else
            printf("Couldn't open saveData file: %s\n", mtp->id);
        }

        MaxMax = MaxAvg = 0;
        for (k=0; k<400; k++)
          MaxHisto[k] = AvgHisto[k] = 0;
	for (k=0; k<mtp->arrayNum; k++) {
          if (mtp->maxArray[k] > gmax)
            gmax = mtp->maxArray[k];
          if (mtp->minArray[k] < gmin)
            gmin = mtp->minArray[k];
          if (k*mtp->timeInc > StartTime) {
            MaxHisto[mtp->maxArray[k]/Bucket]++;
            AvgHisto[mtp->avgArray[k]/Bucket]++;
            if (mtp->maxArray[k] > MaxMax)
              MaxMax = mtp->maxArray[k];
            if (mtp->avgArray[k] > MaxAvg)
              MaxAvg = mtp->avgArray[k];
          }
          gsum += mtp->avgArray[k];
          gcnt++;
          if (gcnt == GroupCnt) {
            psp->array[kk][0] = (2*k+1)*mtp->timeInc/2;
            psp->array[kk][1] = gmax*mtp->div;
            psp->zarray[kk] = gmin*mtp->div;
            psp1->array[kk][0] = (2*k+1)*mtp->timeInc/2;
            psp1->array[kk][1] = gsum/GroupCnt*mtp->div;
            kk++;
            gcnt = gsum = 0;
            gmin = mtp->minArray[k+1];
            gmax = mtp->maxArray[k+1];
          }
/*	  i = (mtp->maxArray[k] + mtp->minArray[k])/2;
	  sum += i;
*/
          sum += mtp->avgArray[k];
	  ii++;
	  if (k == next) {
	    spsp->array[spsp->arrayN][0] = 
	      next*mtp->timeInc - inc*mtp->timeInc/2;
	    spsp->array[spsp->arrayN++][1] = ((float)sum)/ii + .499;
	    next += inc;
	    sum = ii = 0;
	  }
	}
	if (lastTime < k*mtp->timeInc)
	  lastTime = k*mtp->timeInc;
        if (sum != 0) {
	  spsp->array[spsp->arrayN][0] = next*mtp->timeInc -inc*mtp->timeInc/2;
	  spsp->array[spsp->arrayN++][1] = ((float)sum)/ii + .499;
        }
	psp->other = NULL;
	strcpy(psp->ytitle, mtp->id);
	sprintf(psp->gtitle, " ");
        if (JournalFlag)
          sprintf(psp->plotType, "0.2 0 2 plotZbars\n");
        else
	  sprintf(psp->plotType, "0 0 2 plotZbars\n");
	strcpy(psp->id, mtp->id);
	psp->yticRound = 1;
	psp->yticSizeInit = 5;
	psp->yticSizeInc = 5;
	psp->yticMaxNum = 10;
	strcpy(spsp->plotType, "0 %f 6 plotNum\n");
	spsp->minF = 0.0;
	spsp->maxF = 1.0;
	spsp->minMaxF = 0.03;
/*      if (JournalFlag)
          strcpy(psp1->plotType, "1.5 0 plotStraightLines\n");
        else
*/
        if (queueAvgWidth >= 0  &&  queueAvgGray >= 0)
        sprintf(psp1->plotType, "%.2f %.2f 5 plotNAvgStraightLines\n",
                   queueAvgWidth, queueAvgGray);
        qsum = qcount = 0;
	for (k=0; k<spsp->arrayN; k++) {
	  if (fout != NULL)
	    fprintf(fout, "%s%d: %d\n", dbstr, k, spsp->array[k][1]);
	  printf("%3d-%3d Average Queue Size: %3d\n", k*5, (k+1)*5,
		 spsp->array[k][1]);
	  qsum += spsp->array[k][1];
	  qcount++;
	}
	printf("Average Queue Size: %.1f\n", ((double)qsum/qcount));
        for (k=0; k<=MaxMax/Bucket; k++)
          printf("%3d-%3d Histo (max, avg): %6.3f%%, %6.3f%%\n",
                 Bucket*k, Bucket*(k+1)-1, MaxHisto[k]*100.0/mtp->arrayNum,
                 AvgHisto[k]*100.0/mtp->arrayNum);
	if (fout != NULL) {
	  fclose(fout);
	  fout = NULL;
	}
      }
    }
    if (totalBytesDrop > 10000) {
      printf("\ntotalPacketsDropped:%5d, totalBytesDroped:      %dKB\n\n", 
	     totalPacketsDrop, totalBytesDrop/1024);
    }
    else {
      printf("\ntotalPacketsDropped:%5d, totalBytesDroped:      %d\n\n", 
	     totalPacketsDrop, totalBytesDrop);
    }
    if (0 /*tcpPkts*/) {
      mtp = (MaxMinTrace *)itp;
      fout = NULL;
      printf("\nDoing %s\n", "tcpPkts");
      psp = &Plots[PlotsN++];
      psp->zFlag = 1;
      psp->main = 1;
      psp->arrayN = mtp->arrayNum/GroupCnt;
      psp->array = (int (*)[2]) malloc(sizeof(int)*(2*mtp->arrayNum/GroupCnt+12));
      psp->zarray = (int *) malloc(sizeof(int)*(mtp->arrayNum/GroupCnt+12));
      spsp = &Plots[PlotsN++];
      spsp->arrayN = 0;
      spsp->zFlag = 3;
      spsp->main = 0;
      spsp->array = (int (*)[2]) malloc(sizeof(int)*2*100);
        psp1 = &Plots[PlotsN++];
      psp1->zFlag = 0;
      psp1->main = 0;
      psp1->arrayN = mtp->arrayNum/GroupCnt;
      psp1->array = (int (*)[2]) malloc(sizeof(int)*(2*mtp->arrayNum+2));
      next = inc = 5000000/mtp->timeInc;
      sum = ii = 0;
        gmin = mtp->minArray[0];
      gmax = mtp->maxArray[0];
      gsum = gcnt = kk = 0;

      if (SaveDataFlag) {
        FILE *fout;
        k = ((2*BegTime)/mtp->timeInc - 1)/2;
        if ((fout = fopen(mtp->id, "w")) != NULL) {
          printf("Saving data in file: %s\n", mtp->id);
          fwrite(mtp->maxArray + k, sizeof(char), 1024, fout);
          fclose(fout);
        }
        else
          printf("Couldn't open saveData file: %s\n", mtp->id);
      }
      MaxMax = MaxAvg = 0;
      for (k=0; k<400; k++)
        MaxHisto[k] = AvgHisto[k] = 0;
      for (k=0; k<mtp->arrayNum; k++) {
        if (mtp->maxArray[k] > gmax)
          gmax = mtp->maxArray[k];
        if (mtp->minArray[k] < gmin)
          gmin = mtp->minArray[k];
        if (k*mtp->timeInc > StartTime) {
          MaxHisto[mtp->maxArray[k]/Bucket]++;
          AvgHisto[mtp->avgArray[k]/Bucket]++;
          if (mtp->maxArray[k] > MaxMax)
            MaxMax = mtp->maxArray[k];
          if (mtp->avgArray[k] > MaxAvg)
            MaxAvg = mtp->avgArray[k];
        }
        gsum += mtp->avgArray[k];
        gcnt++;
        if (gcnt == GroupCnt) {
          psp->array[kk][0] = (2*k+1)*mtp->timeInc/2;
          psp->array[kk][1] = gmax;
          psp->zarray[kk] = gmin;
          psp1->array[kk][0] = (2*k+1)*mtp->timeInc/2;
          psp1->array[kk][1] = gsum/GroupCnt;
          kk++;
          gcnt = gsum = 0;
          gmin = mtp->minArray[k+1];
          gmax = mtp->maxArray[k+1];
        }
/*      i = (mtp->maxArray[k] + mtp->minArray[k])/2;
        sum += i;
*/
        sum += mtp->avgArray[k];
        ii++;
        if (k == next) {
          spsp->array[spsp->arrayN][0] =
            next*mtp->timeInc - inc*mtp->timeInc/2;
          spsp->array[spsp->arrayN++][1] = ((float)sum)/ii + .499;
          next += inc;
          sum = ii = 0;
        }
      }
      if (lastTime < k*mtp->timeInc)
        lastTime = k*mtp->timeInc;
        if (sum != 0) {
          spsp->array[spsp->arrayN][0] = next*mtp->timeInc -inc*mtp->timeInc/2;
          spsp->array[spsp->arrayN++][1] = ((float)sum)/ii + .499;
        }
      psp->other = NULL;
      strcpy(psp->ytitle, mtp->id);
      sprintf(psp->gtitle, " ");
      if (JournalFlag)
        sprintf(psp->plotType, "0.2 0 2 plotZbars\n");
      else
        sprintf(psp->plotType, "0 0 2 plotZbars\n");
      strcpy(psp->id, mtp->id);
      psp->yticRound = 1;
      psp->yticSizeInit = 5;
      psp->yticSizeInc = 5;
      psp->yticMaxNum = 10;
      strcpy(spsp->plotType, "0 %f 6 plotNum\n");
      spsp->minF = 0.0;
      spsp->maxF = 1.0;
      spsp->minMaxF = 0.03;
/*    if (JournalFlag)
        strcpy(psp1->plotType, "1.5 0 plotStraightLines\n");
      else
*/
	strcpy(psp1->plotType, "0.5 1 5 plotNAvgStraightLines\n");
      qsum = qcount = 0;
      for (k=0; k<spsp->arrayN; k++) {
        if (fout != NULL)
          fprintf(fout, "%s%d: %d\n", dbstr, k, spsp->array[k][1]);
        printf("%3d-%3d Average Queue Size: %3d\n", k*5, (k+1)*5,
               spsp->array[k][1]);
        qsum += spsp->array[k][1];
        qcount++;
      }
      printf("Average Queue Size: %.1f\n", ((double)qsum/qcount));
      for (k=0; k<=MaxMax/Bucket; k++)
        printf("%3d-%3d Histo (max, avg): %6.3f%%, %6.3f%%\n",
               Bucket*k, Bucket*(k+1)-1, MaxHisto[k]*100.0/mtp->arrayNum,
               AvgHisto[k]*100.0/mtp->arrayNum);
      if (fout != NULL) {
        fclose(fout);
        fout = NULL;
      }
   }

    sprintf(HeadStr[HeadStrN++], 
	    "Packets dropped: (%d, %d), KBytes dropped: (%.1f, %.1f)",
	    totalPacketsDrop, rangePacketsDrop, totalBytesDrop/1024.0,
	    rangeBytesDrop/1024.0);
/*     Events[EventsN].event = E_DROP; */
/*     Events[EventsN].symbol = P_VBAR; */
/*     Events[EventsN].minF = 1.0; */
/*     Events[EventsN].maxF = 0.0; */
/*     Events[EventsN++].minMaxF = 0.0; */
    ADD_EVENT(E_DROP, P_VBAR, 1.0, 0.0, 0.0);
    if (PlotFlag)
      initPlot(Argc, Argv, lastTime, ts->protocol);
    pktPrint();
    return;
  }

  if (queueLastTime < lastTime) {
    ii = lastTime - queueLastTime;
    if (queueLastSize > 0) {
      queueBusy[timeIndex] += ii;
      queueBusyT += ii;
    }
    else {
      queueNonBusy[timeIndex] += ii;
      queueNonBusyT += ii;
    }
  }
  printf("\n\n");

  if (queueBusyT > 0) {
    if (dbName != NULL) 
      fout = fopen(dbName, "a");

    for (k=0; k<=queueMax; k++) {
      printf("Queue Size %2d:  %3d %03d %03d   (%5.1f%%)\n", k, 
	     queueSizeTimes[k]/1000000,
	     (queueSizeTimes[k]%1000000)/1000, queueSizeTimes[k]%1000, 
	     100.0*((float)queueSizeTimes[k])/((float)lastTime));
      if (fout != NULL)
	fprintf(fout, "q%d: %.1f\n", k, 
		100.0*((float)queueSizeTimes[k])/((float)lastTime));
    }
    if (fout != NULL) {
      for (i=k; k<=10; k++)
	fprintf(fout, "q%d: 0.0\n", k);
    }
    printf("\n");
    for (k=0; k<=timeIndex; k++) {
/*       printf("%3d-%3d Queue non-Busy:  %3d %03d %03d   (%5.1f%%)\n",  */
/* 	     k*timeInc/1000000, (k+1)*timeInc/1000000, */
/* 	     queueNonBusy[k]/1000000, */
/* 	     (queueNonBusy[k]%1000000)/1000, queueNonBusy[k]%1000,  */
/* 	     100.0*((float)queueNonBusy[k])/((float)timeInc)); */
      printf("%3d-%3d Queue Busy:  %3d %03d %03d   (%5.1f%%)\n", 
	     k*timeInc/1000000, (k+1)*timeInc/1000000, queueBusy[k]/1000000,
	     (queueBusy[k]%1000000)/1000, queueBusy[k]%1000, 
	     100.0*((float)queueBusy[k])/((float)timeInc));
      Busy[BusyN][1] = 100*(queueBusy[k])/(timeInc);
      Busy[BusyN++][0] = timeInc*(2*k+1)/2;
      if (fout != NULL)
	fprintf(fout, "b%d: %.1f\n", k*timeInc/1000000, 
		100.0*((float)queueBusy[k])/((float)timeInc));
    }
/*     printf("Total   Queue non-Busy:  %3d %03d %03d   (%5.1f%%)\n", */
/* 	   queueNonBusyT/1000000, */
/* 	   (queueNonBusyT%1000000)/1000, queueNonBusyT%1000,  */
/* 	   100.0*((float)queueNonBusyT)/((float)ts->lastTime)); */
    printf("\nTotal   Queue Busy:  %3d %03d %03d   (%5.1f%%)\n\n", 
	   queueBusyT/1000000,
	   (queueBusyT%1000000)/1000, queueBusyT%1000, 
	   100.0*((float)queueBusyT)/((float)ts->lastTime));
    sprintf(HeadStr[HeadStrN++], "Queue Busy %5.1f%%", 
	    100.0*((float)queueBusyT)/((float)ts->lastTime));
    if (fout != NULL) {
      fprintf(fout, "total busy: %.1f\n", 
	      100.0*((float)queueBusyT)/((float)ts->lastTime));
    }
/*     printf("nonBusy+Busy: %d, lastTime:%d\n", queueNonBusy+queueBusy, */
/* 	   ts->lastTime); */
  }
  else {
    printf("totalPacketsSent:   %5d, totalKBytesSent:        %dKB\n\n",
	   totalPacketsSent, totalBytesSent/1024);
    printf("totalCollisions:    %5d, totalKBytesInCollisions:%dKB\n\n", 
	   totalPacketsCollision, totalBytesCollision/1024);
  } 
  if (totalBytesDrop > 10000)
    printf("totalPacketsDropped:%5d, totalBytesDroped:      %dKB\n\n", 
	   totalPacketsDrop, totalBytesDrop/1024);
  else {
    printf("totalPacketsDropped:%5d, totalBytesDroped:      %d\n\n", 
	   totalPacketsDrop, totalBytesDrop);
  }
  if (fout != NULL) {
    fprintf(fout, "KB dropped: %.1f\n", ((float)totalBytesDrop)/1024.0);
    fprintf(fout, "pk dropped: %d\n", totalPacketsDrop);
    fclose(fout);
  }
  if (PlotFlag  &&  (ts->protocol == TRACE_ROUTER_FCFS || ts->protocol == TRACE_ROUTER_RED)) {
    sprintf(HeadStr[HeadStrN++], "Input Packets: %d, Input KB: %d, Avg throughput: %.1f KB/s", 
	    inTotalSumPackets[1], inTotalSumBytes[1]/1024, 
	    ((float)inTotalSumBytes[1])/(1024.0*(lastTime/1000000.0)));
    sprintf(HeadStr[HeadStrN++], "Packets dropped: %d, KBytes dropped: %.1f",
	    totalPacketsDrop, ((float)totalBytesDrop)/1024.0);
  }

  if (PlotFlag)
    initPlot(Argc, Argv, lastTime, ts->protocol);

}

/* 
 * These stub routines are included to avoid linking in msg.c.
 */
void *msgWalkToughNext(cxt, len)
MsgWalk *cxt;
int     *len;
{ fprintf(stderr, "Remove this Stub for msgWalkToughNext !! \n"); exit(-1); }

void msgToughDestroy(n)
MsgNode n;
{ fprintf(stderr, "Remove this Stub for msgToughDestroy!!\n"); exit(-1); }
