#include "copyright.h"
/****************************************************************** 
 *
 * calculationclass.c --
 *
 *     Handle details of calculation functions.
 *     Each calculationclass instance represents one calculation.
 *
 *
 * Author : Dan Gunter
 * Created: 24 June 1998
 *
 * $Author: mstoufer $
 * $Source: /home/g2/src/projects/NetLogger/src/nlv/old/calculationclass.c,v $
 * $RCSfile: calculationclass.c,v $
 * $Revision: 1.1.1.1 $
 * $Locker:  $
 * $Date: 2000/12/05 19:52:33 $
 *
 * Modification history
 * --------------------
 *
 ****************************************************************** 
 */
static char rcsid[] = "$Id: calculationclass.c,v 1.1.1.1 2000/12/05 19:52:33 mstoufer Exp $";

#include "calculationclass.h"

/*========= DATA =====================================================*/

#define T Nlv_cc
struct T {
  Nlv_CalcFn      fn;
  Nlv_ClearFn     clearFn;
  Nlv_CalcResult *results;
  int             numResults;
  int             changed;
  int             vecSize;
  int             otherSize;
  char           *name;
  unsigned char   keysetShow[ NLV_MAX_KEYSETS ]; /* Nth bit indicates 1=yes, 0=no */
  struct t_node  *fnTreePtr;
};

#define FILE_ERR_CODE 400

/*========= FUNCTIONS ================================================*/

#define NLV_ITERSLOT(x) this->results[((x) + 1)*(this->vecSize + this->otherSize) - 1]

/*
 *----------------------------------------------------------------------
 *
 * New -- Allocate new object.
 *
 * Calls: malloc
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

T Nlv_ccNew( )
{
  T this = (T)Nlv_Malloc( sizeof( struct Nlv_cc ) );

  this->name       = NULL;
  this->results    = (Nlv_CalcResult *)malloc( sizeof(Nlv_CalcResult) );
  this->vecSize    = 1;
  this->otherSize  = 0;
  this->numResults = 1;
  this->changed    = 0;
  this->fnTreePtr  = NULL;

  return this;
}

/*
 *----------------------------------------------------------------------
 *
 * SetName -- Set the name of the calculation.
 *
 * Calls    : malloc, ?free
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccSetName( T this, char *newName )
{
  if ( this->name )
    free( this->name );
  if ( !newName )
    this->name = NULL;
  else {
    this->name = (char*)malloc( strlen(newName) + 1 );
    strcpy( this->name, newName );
  }
}

/*
 *----------------------------------------------------------------------
 *
 * SetKeysetShow -- Set the keyset "show" mask for the calculation.
 *
 * Calls    : Nlv_kyGetNumKeysets, Nlv_kyGetCalcShow,
 *            Tcl_FirstHashEntry, Tcl_NextHashEntry
 *
 * Algorithm: 
 *            - Set mask to NO for all possible keysets.
 *            - Iterate through keyset hashtable
 *            - If show is YES, put a '1' in that position in 
 *              the mask.
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccSetKeysetShow( T this, Nlv_ky ky )
{
  Tcl_HashTable *ksTbl;
  Tcl_HashEntry *e;
  Tcl_HashSearch srch;
  Nlv_KeySet *value;
  int idx;

  memset( this->keysetShow, (unsigned char)0, sizeof(this->keysetShow) );
  ksTbl = Nlv_kyGetKeySetTbl( ky ); 
  for ( e = Tcl_FirstHashEntry( ksTbl, &srch ); e != NULL ; e = Tcl_NextHashEntry(&srch) ) {
    value = (Nlv_KeySet *)Tcl_GetHashValue( e );
    if ( 1 == Nlv_kyGetCalcShow( ky, value, this->name ) ) {
      idx = value->index;
      if ( idx > NLV_MAX_KEYSETS )
	continue;
      this->keysetShow[ idx / 8 ] |= (unsigned int)1 << (idx % 8);
    }
  }
}

/*
 *----------------------------------------------------------------------
 *
 * GetKeySetShow -- Get 1/0 value for showing this calculation in
 *                  this keyset.
 *
 * Calls:
 *
 * Algorithm: Shmancy accessor.
 *
 *----------------------------------------------------------------------
 */
int Nlv_ccGetKeySetShow( T this, int ksIndex )
{
  unsigned char bit=1;

  return (int)(this->keysetShow[ ksIndex / 8 ] & ( bit << (ksIndex % 8)));
}

/*
 *----------------------------------------------------------------------
 *
 * GetName -- Get the name of the calculation, or a special non-name
 *            if there is none (thus, not breaking strcmp() ).
 *
 * Calls    :
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

char *Nlv_ccGetName( T this )
{
  if ( this->name )
    return this->name;
  else
    return "__NONE__";
}

/*
 *----------------------------------------------------------------------
 *
 * SetCapacity -- Set the number of results that can be held in the
 *                array. This uses the 'vecSize' & 'otherSize' vars.
 *
 * Calls    : malloc
 *
 * Algorithm: Each result "slot" can hold data for one client.
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccSetCapacity( T this, int slots )
{
  int sz;

  if ( slots < 1 )
    return;
  if ( this->results )
    free( this->results );
  sz = slots * ( this->vecSize + this->otherSize );
  this->results    = (Nlv_CalcResult *)malloc( sz * sizeof(Nlv_CalcResult) );
  this->numResults = slots;
}

/*
 *----------------------------------------------------------------------
 *
 * GetSize -- Get the number of results in array.
 *
 * Calls    :
 *
 * Algorithm: Accessor.
 *
 *----------------------------------------------------------------------
 */
int Nlv_ccGetSize( T this )
{
  return this->numResults;
}


/*
 *----------------------------------------------------------------------
 *
 * SetFunctions -- Set the function to call for processing, clearing.
 *
 * Calls    : 
 *
 * Algorithm: Accessor.
 *
 *----------------------------------------------------------------------
 */
void  Nlv_ccSetFunctions( T this, Nlv_CalcFn fn1, Nlv_ClearFn fn2)
{
  this->fn = fn1;
  this->clearFn = fn2;
}

/*
 *----------------------------------------------------------------------
 *
 * GetResult -- Get a pointer to value from the i-th data slot.
 *
 * Calls    :
 *
 * Algorithm: Very simple.
 *
 *----------------------------------------------------------------------
 */

Nlv_CalcResult *Nlv_ccGetResult( T this, int slot )
{
  if ( slot < 0 && slot >= this->numResults )
    return NULL;
  return (this->results + slot * (this->vecSize+this->otherSize) );
}

/*
 *----------------------------------------------------------------------
 *
 * GetIter -- Get number of iterations included in this calculation.
 *
 * Calls    :
 *
 * Algorithm: Iterations are always the last data element in the
 *            "other" section.
 *
 *----------------------------------------------------------------------
 */
long Nlv_ccGetIter( T this, int slot )
{
  return (long)NLV_ITERSLOT(slot);
}

/*
 *----------------------------------------------------------------------
 *
 * GetVecSize -- Get size of data vector within returned result.
 *
 * Calls    :
 *
 * Algorithm: Very simple (accessor).
 *
 *----------------------------------------------------------------------
 */
int Nlv_ccGetVecSize( T this )
{
  return this->vecSize;
}


/*
 *----------------------------------------------------------------------
 *
 * SetParam -- Set result parameters (this only needs
 *             to be done once per calculation).
 *
 * Calls    :
 *
 * Algorithm: "vecSize" means the size of the data used for the
 *            result, and "otherSize" is the size of the array used
 *            for storage but NOT result. By convention, the data
 *            always comes first. Thus, each client takes:
 *               (vecSize + otherSize)*sizeof(Nlv_CalcResult)
 *            bytes of storage.
 *
 *----------------------------------------------------------------------
 */

void Nlv_ccSetParam( T this, int vecSize, int otherSize )
{
  this->vecSize   = vecSize;
  this->otherSize = otherSize + 1; /* 1 extra for iterations */
}

/*
 *----------------------------------------------------------------------
 *
 * Process -- Perform the main calculation.
 *
 * Calls    :
 *
 * Algorithm: Wrapper for the calculation function itself.
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccProcess( T this, Nlv_AData *dataPtr )
{
  (*this->fn)( this, dataPtr );
}

/*
 *----------------------------------------------------------------------
 *
 * AddIter -- Add to iteration count for client.
 *
 * Calls    :
 *
 * Algorithm: Use our happy little macro.
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccAddIter( T this, int client )
{
  NLV_ITERSLOT(client)++;
}

/*
 *----------------------------------------------------------------------
 *
 * Clear -- Clear data calculated in preparation for new window.
 *
 * Calls    :
 *
 * Algorithm: Wrapper for the clear function.
 *            Also clear iterations to 0.
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccClear( T this, int numClients )
{	    
  int i;

  (*this->clearFn)( this, numClients );
  for (i=0; i < numClients; i++ )
    NLV_ITERSLOT(i) = 0.;
}

/*
 *----------------------------------------------------------------------
 *
 * NewParams -- Start the parameter structure list with the default
 *              values for the built-in calculations, which currently
 *              are latency and throughput.
 *
 * Calls    :
 *
 * Algorithm: Allocate and fill in values. All hardcoded.
 *
 *----------------------------------------------------------------------
 */

void Nlv_ccNewParams( Nlv_CalcParam **pp, int *n )
{
  Nlv_CalcParam *p; /* make life easier */
  int            i;

 *n  = 2;
 *pp = p = (Nlv_CalcParam *) malloc ( (*n) * sizeof(Nlv_CalcParam) );

 for ( i = 0; i < *n; i++ )
   Nlv_ccInitParam( &p[i] );

 p[ 0 ].name = strdup(THROUGHPUT_STR);
 p[ 1 ].name = strdup(LATENCY_STR);

 return;
}

/*
 *----------------------------------------------------------------------
 *
 * InitParam -- Set initial calculation parameter values.
 *
 * Calls    :
 *
 * Algorithm: 
 *
 *----------------------------------------------------------------------
 */

void Nlv_ccInitParam( Nlv_CalcParam * p )
{
  p->name      = NULL;
  p->show      = 1;
  p->precision = 4;
}


/*
 *----------------------------------------------------------------------
 *
 * SetFnTreePtr -- Set the pointer to the expression tree, for
 *                 user-defined calculations.
 *
 * Calls    :
 *
 * Algorithm: <accessor>
 *
 *----------------------------------------------------------------------
 */
void Nlv_ccSetFnTreePtr( T this, struct t_node *ptr )
{
  this->fnTreePtr = ptr;
}

#undef T
#undef FILE_ERR_CODE
