#include "copyright.h"
/****************************************************************** 
 *
 * analysisclass.c --
 *
 *     Interface to analysis class.
 *
 *
 * $Author: mstoufer $
 * $Source: /home/g2/src/projects/NetLogger/src/nlv/old/analysisclass.c,v $
 * $RCSfile: analysisclass.c,v $
 * $Revision: 1.1.1.1 $
 * $Locker:  $
 * $Date: 2000/12/05 19:52:33 $
 *
 ****************************************************************** 
 */
static char rcsid[] = "$Id: analysisclass.c,v 1.1.1.1 2000/12/05 19:52:33 mstoufer Exp $";

#include <sys/types.h>
#include "analysisclass.h"
#include "cacheclass.h"
#include "errclass.h"



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

#define T Nlv_an

struct Nlv_anCalcNode;
typedef struct Nlv_anCalcNode {
  Nlv_cc                 calc;             /* Calculation data */
  struct Nlv_anCalcNode *next;             /* Next node in linked-list */
} Nlv_anCalcNode;

struct T {
  Nlv_anCalcNode *calcList;
  int             numCalcs;
  Nlv_Bounds      window;
  struct Nlv_ca  *cache;
  Nlv_filterFn    inWindow;
  Nlv_filterFn    leftOfWindow;
  int             analysisMode;
  int             analyzing;
};

extern Nlv_err eobj;
#define FILE_ERR_CODE 200

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

/* internal */
void Nlv_anDoCalc( T this );

/*---------- Return 1 if in window, 0 otherwise -----------------------*/
int Nlv_anInWindowFn( void *bounds, void *data )
{
  Nlv_AData *d  = (Nlv_AData *)data;
  Nlv_Bounds *b = (Nlv_Bounds *)bounds;

  if ( d->gdata->time < b->x[0] || d->gdata->time > b->x[1] )
    return 0;
  return 1;
}
/*---------- Return 1 if left of window, 0 otherwise -------------------*/
int Nlv_anLeftOfWindowFn( void *bounds, void *data )
{
  Nlv_AData *d  = (Nlv_AData *)data;
  Nlv_Bounds *b = (Nlv_Bounds *)bounds;

  if ( d->gdata->time < b->x[0] )
    return 1;
  return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * New -- Allocate new object.
 *
 * Calls: malloc
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

T Nlv_anNew( )
{
  T this = (T)malloc( sizeof (struct T) );
  this->calcList = NULL;
  this->numCalcs = 0;
  this->window.x[0] = 0.;
  this->window.x[1] = 0.;
  this->window.y[0] = 0.;
  this->window.y[1] = 9999.;
  this->cache = Nlv_caNew();
  Nlv_caSetCapacity( this->cache, 32767 );
  this->inWindow     = Nlv_anInWindowFn;
  this->leftOfWindow = Nlv_anLeftOfWindowFn;
  this->analysisMode = 1;
  this->analyzing    = 0; 
  return this;
}


/*
 *----------------------------------------------------------------------
 *
 * Process -- Process a piece of analysis data.
 *
 * Calls    : Nlv_caAdd
 *
 * Algorithm: Add it to the cache.
 *            Re-size the cache if it is full.
 *
 *----------------------------------------------------------------------
 */

int Nlv_anProcess( T this, Nlv_AData * anDataPtr )
{
  if ( 0 != Nlv_caAdd( this->cache, anDataPtr ) ) {
    Nlv_caSetCapacity( this->cache, 2 * Nlv_caGetSize(this->cache) );
    if ( 0 != Nlv_caAdd( this->cache, anDataPtr ) )
      return -1;
  }
  return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * AnalyzeWindow -- Analyze current time window.
 *
 * Calls    : Nlv_anDoCalc, Nlv_anClearWindow
 *
 * Algorithm: 
 *            - If analysis mode is off, clear window and exit.
 *            - Clear analysis data for each function.
 *            - Do the calculations for the window.
 *
 *----------------------------------------------------------------------
 */

void Nlv_anAnalyzeWindow( T this, int numClients )
{
  int i;
  Nlv_anCalcNode *curNode;

  this->analyzing = 1;

  if ( this->analysisMode == 0 ) {
    Nlv_anClearWindow( this );
    return;
  }

  for ( i=0, curNode = this->calcList; 
	i < this->numCalcs; 
	i++, curNode=curNode->next )
    Nlv_ccClear( curNode->calc, numClients );
  
  Nlv_anDoCalc( this );
}

/*
 *----------------------------------------------------------------------
 *
 * AnalyzeWindowContinued -- Analyze current time window, but don't
 *                           clear the calculations first.
 *
 * Calls    : Nlv_anDoCalc, Nlv_anClearWindow
 *
 * Algorithm: 
 *            - If analysis mode is off, clear window and exit.
 *            - Do the calculations for the window.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anAnalyzeWindowContinued( T this, int numClients )
{
  if ( this->analysisMode == 0 ) {
    Nlv_anClearWindow( this );
    return;
  }
  Nlv_anDoCalc( this );
}

/*
 *----------------------------------------------------------------------
 *
 * AnalyzeWindowDone -- Set flag to indicate that we are not
 *                      analyzing this window.
 * Calls    : <none>
 *
 * Algorithm: set flag "analyzing"
 *
 *----------------------------------------------------------------------
 */
void Nlv_anAnalyzeWindowDone( T this )
{
  this->analyzing = 0;
}

/*
 *----------------------------------------------------------------------
 *
 * AnalyzeWindowIsStarted -- Get flag indicating whether we are busy
 *                           analyzing this window.
 * Calls    : <none>
 *
 * Algorithm: return integer flag value
 *
 *----------------------------------------------------------------------
 */
int
Nlv_anAnalyzeWindowIsStarted( T this )
{
  return this->analyzing;
}

/*
 *----------------------------------------------------------------------
 *
 * DoCalc -- Perform calculations
 *
 * Calls    : Nlv_caReentrantRemove, Nlv_caReentrantExamine,
 *            Nlv_caReentrantClear, Nlv_ccProcess
 *
 * Algorithm: 
 *            - Examine all elements within window.
 *              + Apply a filter so only certain keysets are considered.
 *              + Call analysis function(s) for each.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anDoCalc( T this )
{
  int i;
  Nlv_AData      *dataPtr;
  Nlv_anCalcNode *curNode;

  Nlv_caReentrantClear( this->cache );
  while( (dataPtr = Nlv_caReentrantExamine( this->cache, 
				 this->inWindow, 
				 (void *)&this->window )) ) {
    for ( i=0, curNode=this->calcList;
	  i < this->numCalcs;
	  i++, curNode=curNode->next ) {
      if ( Nlv_ccGetKeySetShow( curNode->calc, dataPtr->gdata->eventSet ) ) {
	Nlv_ccProcess( curNode->calc, dataPtr );
      }
    }
  }
}


/*
 *----------------------------------------------------------------------
 *
 * ClearWindow -- Remove all points from analysis window.
 *
 * Calls    : Nlv_caReentrantRemove, Nlv_caReentrantClear
 *
 * Algorithm: Walk through cache with inWindow filter until no more
 *            to remove, freeing as we go.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anClearWindow( T this )
{
  Nlv_AData      *dataPtr;
  int i;
  Nlv_anCalcNode *cur;

  Nlv_caReentrantClear( this->cache );
  while( (dataPtr = Nlv_caReentrantRemove( this->cache, NULL, NULL)) ) {
    FREE_ADATA( dataPtr );
  }
}  

/*
 *----------------------------------------------------------------------
 *
 * UpdateWindow -- Remove all points which are earlier than the
 *                 current left edge of the display from the
 *                 analysis window.
 *
 * Calls    : Nlv_caReentrantRemove, Nlv_caReentrantClear
 *
 * Algorithm: Walk through cache with inWindow filter until no more
 *            to remove, freeing as we go.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anUpdateWindow( T this )
{
  Nlv_AData      *dataPtr;
  int i;
  Nlv_anCalcNode *cur;

  Nlv_caReentrantClear( this->cache );
  while( (dataPtr=Nlv_caReentrantRemove( this->cache, 
					 this->leftOfWindow, 
					 (void *)&this->window)) ) {
    FREE_ADATA( dataPtr );
  }
}  

/*
 *----------------------------------------------------------------------
 *
 * AddCalc -- Add a calculation to the mix. Return Id.
 *
 * Calls    :
 *
 * Algorithm: The calculation instance is pointed at.
 *
 *----------------------------------------------------------------------
 */

int Nlv_anAddCalc( T this, Nlv_cc calcPtr )
{
  int i;
  Nlv_anCalcNode *cur, *p;

  /* Point 'p' at the new node to be added */
  if ( !this->calcList ) {
    p = this->calcList = ( Nlv_anCalcNode *)malloc( sizeof(Nlv_anCalcNode) );
  }
  else {
    cur = this->calcList;
    for ( i=1; i < this->numCalcs; i++, cur=cur->next );
    p = cur->next = ( Nlv_anCalcNode *)malloc( sizeof(Nlv_anCalcNode) );
  }
  /* Fill in the data for the new node */
  p->calc = calcPtr;
  p->next = NULL;
  /* Increment number of calculations and return it */
  this->numCalcs++;
  return this->numCalcs;
}


/*
 *----------------------------------------------------------------------
 *
 *  GetCalc -- Get a calculation (pointer) by its ID (returned by
 *             AddCalc, above ).
 *
 * Calls    :
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

Nlv_cc Nlv_anGetCalc( T this, int calcId )
{
  int i;
  Nlv_anCalcNode *cur;

  if ( calcId < 0 && calcId >= this->numCalcs ) 
    return NULL;
  for ( cur = this->calcList, i = 0; i < calcId; i++, cur=cur->next );
  return cur->calc;
}

/*
 *----------------------------------------------------------------------
 *
 * GetCalcByName -- Get a calculation pointer by its name.
 *
 * Calls    :
 *
 * Algorithm: Linear search for the name of the calculation.
 *
 *----------------------------------------------------------------------
 */

Nlv_cc Nlv_anGetCalcByName( T this, char *calcName )
{
  int i;
  Nlv_anCalcNode *cur = NULL;  

  for ( i=0; 
	i < this->numCalcs && strcmp( calcName, Nlv_ccGetName(cur->calc)); 
	i++, cur=cur->next );
  if ( i >= this->numCalcs )
    return NULL;
  return cur->calc;
}

/*
 *----------------------------------------------------------------------
 *
 * SetWindow -- Set the window size.
 *
 * Calls    :
 *
 * Algorithm:  Ignore y-axis, for now.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anSetWindow( T this, Nlv_Bounds *b )
{
  this->window.x[0] = b->x[0];
  this->window.x[1] = b->x[1];
}

/*
 *----------------------------------------------------------------------
 *
 * GetWindow -- Get the window size.
 *
 * Calls    :
 *
 * Algorithm:  Accessor.
 *
 *----------------------------------------------------------------------
 */
Nlv_Bounds *Nlv_anGetWindow( T this )
{
  return &this->window;
}

/*
 *----------------------------------------------------------------------
 *
 * SetAnalysisMode -- Set the integer that indicates whether to
 *                   calculate or show calculations.
 *
 * Calls    :
 *
 * Algorithm:  Accessor.
 *
 *----------------------------------------------------------------------
 */
void Nlv_anSetAnalysisMode( T this, int v )
{
  this->analysisMode = v;
}

/*
 *----------------------------------------------------------------------
 *
 * GetAnalysisMode -- Get the integer that indicates whether to
 *                   calculate or show calculations.
 *
 * Calls    :
 *
 * Algorithm:  Accessor.
 *
 *----------------------------------------------------------------------
 */
int Nlv_anGetAnalysisMode( T this )
{
  return this->analysisMode;
}
#undef T
#undef FILE_ERR_CODE
