/*
 * Copyright 1993 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any expressed or implied warranty.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "global.h"
#include "gnuplotcommand.h"
#define  HISTCLASS 50
/*-------------------------------------------------------*/
/*---------------- Distribution histram -----------------*/
/*-------------------------------------------------------*/
int
  make_dist_macro(fd,S,SD)
FILE* fd;
STAT_param* S;
STAT* SD;
{
  char title_str[256], xaxis_str[256];
  char label1[256],label2[256],label3[256];
  float posx, posy, pos2y, xmax, ymax;
  fprintf(fd,headmsg);
  fprintf(fd,general_str);
  /*------ set labels ------*/
  sprintf(title_str,"Distribution of %s per %s",
                      atm_mode_str[S->atm_mode],scope_str[S->scope]);
  sprintf(xaxis_str,"Number of %s per %s",
                      atm_mode_str[S->atm_mode],scope_str[S->scope]);
  fprintf(fd,label_str,title_str, xaxis_str,"Probability");
  /*------ Make stat label ------*/
  sprintf(label1,stat_str[0+S->atm_mode], SD->avg ,SD->sd ,SD->max);
  sprintf(label2,stat_str[2+S->atm_mode], SD->avgl,SD->sdl,SD->maxl);
  sprintf(label3,stat_str[4+S->atm_mode], SD->avgs,SD->sds,SD->maxs);

  switch(S->priority) {
    case 1:  xmax = SD->max;  ymax = SD->distmax;  break;
    case 2:  xmax = SD->maxl; ymax = SD->distmaxl; break;
    case 3:  xmax = SD->maxs; ymax = SD->distmaxs; break;
    default: xmax = (SD->max > SD->maxl) ? SD->max : SD->maxl;
             ymax = (SD->distmax>SD->distmaxl) ? SD->distmax : SD->distmaxl; 
  }
  fprintf(fd,xrange_str,0.0,xmax * 1.10);
  fprintf(fd,yrange_str,0.0,ymax * 1.05);
  /*------ Make stat label ------*/
  posx  = xmax / 10.0;
  posy  = ymax ;
  pos2y = ymax * 0.95;

  switch(S->priority) {
    case 0: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label1, posx,posy);
            fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label2, posx,pos2y);
            break;
    case 1: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label1, posx,posy);
            break;
    case 2: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label2, posx,posy);
            break;
    case 3: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label3, posx,posy);
            break;
  }
  /*------ plot itself ------*/
  fprintf(fd,dist_plot_str[S->priority],S->plot_data_name,S->plot_data_name);
  fprintf(fd,pause_str);
  /*------ postscript output option ------*/
  if(S->ps_out)
    fprintf(fd,ps_str,S->ps_file_name);
  return 0;
}

int
  make_dist_data(fd,SD)
FILE* fd;
STAT* SD;
{
  int i,class;
  int step; /* step of histgram */
  int base = 0;
  int max, min;
  int dist[HISTCLASS],distl[HISTCLASS],dists[HISTCLASS];
  float d,dl,ds;
  /*------ find range of histgram ------*/
  max = SD->maxs + 1;
  if(SD->minl == 0) 
    min = SD->mins -1;
  else 
    min =  SD->minl -1;
  step =  ((max - min) - 1) / HISTCLASS + 1;
  if(HISTCLASS * step < max) base = min;
#ifdef DEBUG
  fprintf(stderr,"class= %d, base= %d, step= %d, max= %d, min= %d\n",
              HISTCLASS, base, step, max, min); 
#endif
  /*------ init data ------*/
  for(i=0;i<HISTCLASS;i++) {
    dist [i] = 0;
    distl[i] = 0;
    dists[i] = 0;
  }
  SD->distmax  = 0.0;
  SD->distmaxl = 0.0;
  SD->distmaxs = 0.0;
  /*------ find range of histgram ------*/
  for(i=0;i<SD->num;i++) {
    class = (SD->bit_num [i] - base) / step;
    if((class>=0)&&(class<HISTCLASS)) dist [class]++;
    class = (SD->bit_numl[i] - base) / step;
    if((class>=0)&&(class<HISTCLASS)) distl[class]++;
    class = (SD->bit_nums[i] - base) / step;
    if((class>=0)&&(class<HISTCLASS)) dists[class]++;
  }
  /*------ write to file, gnuplot errorbae format ------*/
  class = HISTCLASS-1; /* get max class */
  for(i=0;i<HISTCLASS;i++) {
    if(dist[i]||distl[i]||dists[i]) class = i;
  }
  for(i=0;i<class+1;i++) {
    d  = dist [i] / (float)SD->num; /* comvert to probability */
    if(d  > SD->distmax ) SD->distmax  = d;
    dl = distl[i] / (float)SD->num;
    if(dl > SD->distmaxl) SD->distmaxl = dl;
    ds = dists[i] / (float)SD->num;
    if(ds > SD->distmaxs) SD->distmaxs = ds;
    fprintf(fd,"%5d %10.7f 0 %10.7f  %10.7f 0 %10.7f  %10.7f 0 %10.7f\n",
                i*step + base, d, d, dl, dl, ds, ds);
  }
  return 0;
}
/*----------------------------------------------------*/
/*---------------- Generation Record -----------------*/
/*----------------------------------------------------*/
int
  make_gen_rec_macro(fd,S,SD)
FILE* fd;
STAT_param* S;
STAT* SD;
{
  char title_str[256];
  char label1[256],label2[256],label3[256];
  float offs, ymax;
  float posx, posy, pos2y;
  int tics_num;
  /*------ write general part ------*/
  fprintf(fd,headmsg);
  fprintf(fd,general_str);
  /*------ set labels ------*/
  sprintf(title_str,"Generation Record of %s per %s",
                      atm_mode_str[S->atm_mode],scope_str[S->scope]);
  fprintf(fd,label_str,title_str,
                      scope_str[S->scope],atm_mode_str[S->atm_mode]);
  /*------ set tics ------*/
  switch(S->scope) {
    case 0: tics_num = SD->num / 30+1;
            break;
    case 1: if(SD->num<SD->slice_num)
              tics_num = SD->num / 30 + 1;
            else
              tics_num = ((SD->num/SD->slice_num) / 30 + 1) * SD->slice_num;
            break;
    case 2: if(SD->num<(SD->mb_num/SD->slice_num))
              tics_num = SD->num/30+1;
            else
               tics_num = ((SD->num/(SD->mb_num/SD->slice_num)) / 30 + 1) *
                            (SD->mb_num/SD->slice_num);
            break;
    default : tics_num = 1;break;
  }
  fprintf(fd,"set xtics 1,%d\n",tics_num);
  /*------ set xrange (2% offset)------*/
  offs = SD->num * 0.02;
  fprintf(fd,xrange_str,1.0-offs,SD->num+offs);
  /*------ set yrange ------*/
  switch(S->priority) {
    case 2 : ymax = SD->maxl; break;
    case 3 : ymax = SD->maxs; break;
    default: ymax = SD->max;
  }
  fprintf(fd,yrange_str,0.0,ymax * 1.05);
  /*------ Make stat label ------*/
  sprintf(label1,stat_str[0+S->atm_mode], SD->avg, SD->sd, SD->max);
  sprintf(label2,stat_str[2+S->atm_mode], SD->avgl,SD->sdl,SD->maxl);
  sprintf(label3,stat_str[4+S->atm_mode], SD->avgs,SD->sds,SD->maxs);
  posx  = (SD->num - 1.0) / 10.0 + 1.0;
  posy  = ymax ;
  pos2y = ymax * .95;
  switch(S->priority) {
    case 0: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label1, posx,posy);
            fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label2, posx,pos2y);
            break;
    case 1: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label1, posx,posy);
            break;
    case 2: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label2, posx,posy);
            break;
    case 3: fprintf(fd,"set label \"%s\" at %.2f, %.2f\n",label3, posx,posy);
            break;
  }
  /*------ plot data ------*/
  fprintf(fd,plot_str[S->priority],S->plot_data_name,S->plot_data_name);
  fprintf(fd,pause_str);
  /*------ postscript output option ------*/
  if(S->ps_out)
    fprintf(fd,ps_str,S->ps_file_name);
  return 0;
}

int
  make_gene_rec_data(fd,SD)
FILE* fd;
STAT* SD;
{
  int i;
  int h,l,sum;
  for(i=0;i<SD->num;i++) {
    h = SD->bit_num[i];
    l = SD->bit_numl[i];
    sum = SD->bit_nums[i];
    fprintf(fd,"%4d %6d %6d %6d\n",i+1,h,l,sum);
  }
  fflush(fd);
#ifdef DEBUG
  fprintf(stderr,"gnuplot data generated\n");
#endif
  return 0;
}
/*------------------------------------------------------*/
/*------------------ Autocorrelation -------------------*/
/*------------------------------------------------------*/
int
  make_autocorr_macro(fd,S,SD)
FILE* fd;
STAT_param* S;
STAT* SD;
{
  char title_str[256];
  float offs, ymin;
  int tics_num;
  fprintf(fd,headmsg);
  fprintf(fd,general_str);
  /*------ set labels ------*/
  sprintf(title_str,"Autocorrelation of %s per %s",
                      atm_mode_str[S->atm_mode],scope_str[S->scope]);
  fprintf(fd,label_str,title_str,
                      scope_str[S->scope],"Autocorreleraion");
  /*------ set tics ------*/
  switch(S->scope) {
    case 0: tics_num = SD->num / 30+1;
            break;
    case 1: if(SD->num<SD->slice_num)
              tics_num = SD->num / 30 + 1;
            else
              tics_num = ((SD->num/SD->slice_num) / 30 + 1) * SD->slice_num;
            break;
    case 2: if(SD->num<(SD->mb_num/SD->slice_num))
              tics_num = SD->num/30+1;
            else
               tics_num = ((SD->num/(SD->mb_num/SD->slice_num)) / 30 + 1) *
                            (SD->mb_num/SD->slice_num);
            break;
    default : tics_num = 1;break;
  }
  fprintf(fd,"set xtics 1,%d\n",tics_num);
  /*------ set range ------*/
  offs = SD->num * 0.02;
  fprintf(fd, xrange_str, 1.0-offs, SD->num + offs);

  switch(S->priority) {
    case 1:  ymin = SD->ac_min;  break;
    case 2:  ymin = SD->ac_minl; break;
    case 3:  ymin = SD->ac_mins; break;
    default: ymin = (SD->ac_min<SD->ac_minl) ? SD->ac_min : SD->ac_minl; 
  }
  if(ymin > 0) ymin = 0;
  fprintf(fd,yrange_str, ymin * 1.05 ,1.05);
  /*------ plot itself ------*/
  fprintf(fd,plot_str[S->priority],S->plot_data_name,S->plot_data_name);
  fprintf(fd,pause_str);
  /*------ postscript output option ------*/
  if(S->ps_out)
    fprintf(fd,ps_str,S->ps_file_name);
  return 0;
}

double*
  get_ac(data,mean,num)
int* data;
double mean;
int  num;
{
  int i,j;
  double* R;
  double norm_factor;
  R = (double*)calloc(num,sizeof(double));
  for(i=0;i<num;i++) {
    for(j=0;j<num-i;j++) {
      R[i] += (data[j]-mean)*(data[j+i]-mean);
    }
    R[i] /= num;
  }
  
  norm_factor = R[0];
  if(norm_factor!=0)
    for(i=0;i<num;i++) {
      R[i] /= norm_factor;
    }
  else
    for(i=0;i<num;i++) {
      R[i] = 1;
    }
  return R;
}

int
  make_autocorr_data(fd,SD)
FILE* fd;
STAT* SD;
{
  int i;
  double *R,*Rl,*Rs;
  R  = get_ac(SD->bit_num ,SD->avg ,SD->num);
  Rl = get_ac(SD->bit_numl,SD->avgl,SD->num);
  Rs = get_ac(SD->bit_nums,SD->avgs,SD->num);

  SD->ac_min  = 1.0;
  SD->ac_minl = 1.0;
  SD->ac_mins = 1.0;

  for(i=0;i<SD->num;i++) {
    fprintf(fd,"%5d %10.7f %10.7f %10.7f\n",i+1,R[i],Rl[i],Rs[i]);
    if(SD->ac_min  > R [i]) SD->ac_min  = R [i];
    if(SD->ac_minl > Rl[i]) SD->ac_minl = Rl[i];
    if(SD->ac_mins > Rs[i]) SD->ac_mins = Rs[i];
  }
  free(R);free(Rl);free(Rs);
  return 0;
}
/*----------------------------------------------------*/
/*----------------- Interarrival Time ----------------*/
/*----------------------------------------------------*/
int
  make_interarr_macro(fd,S,SD)
FILE* fd;
STAT_param* S;
STAT* SD;
{
  float xmax, ymax;
  fprintf(fd,headmsg);
  /*------ set labels ------*/
  fprintf(fd,label_str,"Inter-Arrival Time of ATM packets",
              "Interarrival Time (X second)","Probability");
  /*------ range set ------*/
  switch(S->priority) {
    case 1:  xmax = SD->max;  ymax = SD->distmax;  break;
    case 2:  xmax = SD->maxl; ymax = SD->distmaxl; break;
    case 3:  xmax = SD->maxs; ymax = SD->distmaxs; break;
    default: xmax = (SD->max > SD->maxl) ? SD->max : SD->maxl;
             ymax = (SD->distmax>SD->distmaxl) ? SD->distmax : SD->distmaxl; 
  }
  if(xmax == 0) xmax = (SD->max > SD->maxl)? SD->max : SD->maxl;
  xmax *= 1.10;
  fprintf(fd,xrange_str,0.0,xmax);
  if(ymax <= 0.0) ymax = 1.0;
  ymax *= 1.05;
  if(ymax >  1.0) ymax = 1.0;
  fprintf(fd,yrange_str,0.0,ymax);
  /*------ plot itself ------*/
  fprintf(fd,dist_plot_str[S->priority],S->plot_data_name,S->plot_data_name);
  fprintf(fd,pause_str);
  /*------ postscript output option ------*/
  if(S->ps_out)
    fprintf(fd,ps_str,S->ps_file_name);
  return 0;
}

int*
  get_interarr(data,num,mb_num)
int* data;
int  num;
int  mb_num; /* # of MB's in each frame */
{
  int i,j,k;
  int t1; /* time when last packet was sent */
  int bits = 0;
  int pos;
  int* I;
  I = (int*)calloc(mb_num,sizeof(int));
  for(i=0;i<num/mb_num;i++) { /* iteration per frame */
    t1   = 0;
    bits = 0;
    for(j=0;j<mb_num;j++) {
      pos = i*mb_num+j;
      bits += data[pos];
      if(bits > ATM_BITS) {
        for(k=0;k<bits/ATM_BITS;k++) {
          I[j-t1]++;
	}
        t1 = j;
      }
      bits %= ATM_BITS;
    }
    if(bits!=0) I[j-t1]++;
  }
  return I;
}

int
  make_interarr_data(fd,SD)
FILE* fd;
STAT* SD;
{
  int i,max = 0;
  int *I,*Il,*Is;
  float d = 0.0 ,dl = 0.0 ,ds = 0.0;
  float sum = 0.0, suml = 0.0, sums = 0.0;
  I  = get_interarr(SD->bit_num ,SD->num,SD->mb_num);
  Il = get_interarr(SD->bit_numl,SD->num,SD->mb_num);
  Is = get_interarr(SD->bit_nums,SD->num,SD->mb_num);
  SD->distmax = 0;  /* The max prob of each class */ 
  SD->distmaxl = 0;
  SD->distmaxs = 0;
  SD->max = 0;      /* The max class */
  SD->maxl = 0;
  SD->maxs = 0;
  /*--- find max array number which ccontains non-zero factor ---*/ 
  for(i=0;i<SD->mb_num;i++) {
    if(I[i]||Il[i]||Is[i]) max = i;
    if(I [i]) SD->max  = i;
    if(Il[i]) SD->maxl = i;
    if(Is[i]) SD->maxs = i;
    if(SD->distmax  < I [i]) SD->distmax  = I [i];
    if(SD->distmaxl < Il[i]) SD->distmaxl = Il[i];
    if(SD->distmaxs < Is[i]) SD->distmaxs = Is[i];
    sum  += I [i];
    suml += Il[i];
    sums += Is[i];
  }
  for(i=0;i<max+1;i++) {
    d  = I [i] / sum; /* comvert to probability */
    if(suml !=0)
      dl = Il[i] / suml;
    else
      dl = 0.0;
    ds = Is[i] / sums;
    fprintf(fd,"%5d %10.7f 0 %10.7f  %10.7f 0 %10.7f  %10.7f 0 %10.7f\n",
                i+1, d, d, dl, dl, ds, ds);
  }
  SD->distmax  /= (float)sum;
  if(suml>0.0)
    SD->distmaxl /= (float)suml;
  SD->distmaxs /= (float)sums;
  free(I);free(Il);free(Is);
  return 0;
}
