/*--------------------------------------------------------------------------
                               P O L T E R W R I T E
                            
    Polterwrite is an object for writing POLTI data files. 
    
    copyright: see copyright.h
    
    Uwe Filges, November 2001

    Various edits, added rotation_speed_targets, Mark Koennecke, 2011
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <tcl.h>
#undef VOID
#include "sics.h"
#include "event.h"
#include "counter.h"
#include "HistMem.h"
#include "nxdict.h"
#include "nxutil.h"
#include "motor.h"
#include "sicsvar.h"
#include "polterwrite.h"
#include "sicsvar.h"
#include "nxscript.h"
#include "sicshipadaba.h"

/*
  diaphragm1 - chopper
*/
#define DIA1DIST 8000

/*
   histogram memory name
*/
#define HM "hm"

#define DETRADIUS 3000

typedef struct {
  pObjectDescriptor pDes;
  pHistMem pHist;
  int iNew;
  time_t tUpdate;
  int iInterval;
  int iEnd;
  SConnection *pCon;
  char *dictfile;
  char *pFile;
} Polterdi, *pPolterdi;


/* ------------------- forward declaration of task function --------------*/
static int PoldiTask(void *pData);
static void PoldiUpdate(pPolterdi self, SConnection * pCon);
static void PoldiStart(pPolterdi s, SConnection * pCon);
static void PoldiLink(pPolterdi s, SConnection * pCon);

/*------------------ The Countstart Callback Function ----------------------*/
static int Countstartcallback(int iEvent, void *pEventData, void *pUser)
{
  pPolterdi self = NULL;

  if (iEvent == COUNTSTART) {
    self = (pPolterdi) pUser;
    assert(self);
    self->iNew = 1;
    self->iEnd = 0;
    self->tUpdate = time(NULL);
    self->pCon = (SConnection *) pEventData;
    TaskRegisterN(pServ->pTasker,"POLDIUpdater", PoldiTask, NULL, NULL, self, 1);
    return 1;
  }
  return 1;
}

/*------------------ The Countend Callback Function ----------------------*/
static int Countendcallback(int iEvent, void *pEventData, void *pUser)
{
  pPolterdi self = NULL;

  if (iEvent == COUNTEND) {
    self = (pPolterdi) pUser;
    assert(self);
    self->tUpdate = time(NULL);
    self->iEnd = 1;
    if (self->iNew == 1) {
      PoldiStart(self, self->pCon);
      PoldiLink(self, self->pCon);
    } else {
      PoldiUpdate(self, self->pCon);
    }
    return 1;
  }
  return 1;
}

/*-----------------------------------------------------------------------*/
static void SNError(void *pData, char *text)
{
  SConnection *pCon;

  assert(pData);
  pCon = (SConnection *) pData;
  SCWrite(pCon, text, eError);
}

/*-------------------------------------------------------------------*/
static void writePolterdiGlobal(NXhandle hfil, NXdict hdict,
                                SConnection * pCon)
{
  char pBueffel[512];

  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "etitle", "title");
  SNXFormatTime(pBueffel, 511);

  NXDputalias(hfil, hdict, "estart", pBueffel);
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "iname", "instrument");
  sprintf(pBueffel, "%d", (int) strlen("SINQ, PSI, Switzerland"));
  NXDupdate(hdict, "strdim", pBueffel);
  NXDputalias(hfil, hdict, "sname", "SINQ, PSI, Switzerland");
  sprintf(pBueffel, "%d", (int) strlen("continous spallation source"));
  NXDupdate(hdict, "strdim", pBueffel);
  NXDputalias(hfil, hdict, "stype", "continous spallation source");
  NXDupdate(hdict, "strdim", "132");
}

/*-------------------------------------------------------------------*/
static void writeChopper(NXhandle hfil, NXdict hdict, SConnection * pCon)
{
  pHdb node = NULL;
  float fVal;

  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "cname", "choppername");
  SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "chopperspeed", "crot");
  SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "chopperphase", "cphase");

  node = FindHdbNode(NULL,"/sics/choco/chopper/nspee", NULL);
  if(node != NULL){
      fVal = atof(node->value.v.text);
	  NXDputalias(hfil,hdict,"crottarget",&fVal);
  }
}

/*-------------------------------------------------------------------*/
static void writeDiaphragm1(NXhandle hfil, NXdict hdict,
                            SConnection * pCon)
{
  float dist;

  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia1x", "d1hl");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia1x0", "d1hl");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia1y", "d1hr");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia1y0", "d1hr");
  dist = (float) DIA1DIST;
  NXDputalias(hfil, hdict, "dia1dist", &dist);
}

/*------------------------------------------------------------------*/

static void writeDiaphragm2(NXhandle hfil, NXdict hdict,
                            SConnection * pCon)
{

  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2x_plus", "d2hl");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2xplus0", "d2hl");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2x_minus", "d2hr");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2xminus0", "d2hr");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2z_plus", "d2vu");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2zplus0", "d2vu");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2z_minus", "d2vl");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2zminus0", "d2vl");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2z_x", "d2x");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2z_x0", "d2x");

  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "dia2dist",
                  "dia1_dia2");
}
/*---------------------------------------------------------------------*/
static void writeCollimator(NXhandle hfil, NXdict hdict,
                            SConnection * pCon)
{
  char pBueffel[50];

  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "cov", "cov");
  memset(pBueffel,0,sizeof(pBueffel));
  Tcl_Eval(InterpGetTcl(pServ->pSics),"coll");
  strncpy(pBueffel,Tcl_GetStringResult(InterpGetTcl(pServ->pSics)), 49);
   NXDputalias(hfil, hdict, "collpos", pBueffel);
}

/*--------------------------------------------------------------------*/
static void writeSample(NXhandle hfil, NXdict hdict, SConnection * pCon)
{
  pSicsVariable active = NULL;
  int iActive;
  CommandList *pCom = NULL;

  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "sdist", "dia2_sample");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "chopperdist",
                  "chopper_sample");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "saname", "sample");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "senvir",
                  "environment");

  if ((pCom = FindCommand(pServ->pSics, "temperature"))
      != NULL) {
    SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "temperature",
                    "stemp");
  }
  active = FindCommandData(pServ->pSics, "activetable", "SicsVariable");
  if (active != NULL) {
    VarGetInt(active, &iActive);
    if (iActive == 1) {
      SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsu", "rsu");
      SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsu0", "rsu");
      SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsl", "rsl");
      SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsl0", "rsl");
      SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsa", "rsa");
      SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsa0", "rsa");
    }
  }

  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sshu", "shu");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "sshu0", "shu");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sshl", "shl");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "sshl0", "shl");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssgu", "sgu");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssgu0", "sgu");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssgl", "sgl");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssgl0", "sgl");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssv", "sv");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssv0", "sv");
  SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssa", "sa");
  SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssa0", "sa");

  pCom = FindCommand(pServ->pSics,"chi");
  if(pCom != NULL){
    SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "schi", "chi");
    SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "schi0", "chi");
    SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sphi", "phi");
    SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "sphi0", "phi");
  }
  
}

/*--------------------------------------------------------------------*/

static void PoldiStart(pPolterdi self, SConnection * pCon)
{
  char pBueffel[256];
  NXhandle hfil = NULL;
  NXdict hdict = NULL;
  int status;
  const float *fTime = NULL;
  CounterMode eMode;
  float *fTime2 = NULL, fTheta0[801], fTheta[801], fVal;
  pSicsVariable pVar = NULL;
  float det_radius, det_size, x0det, y0det, twothet;
  float pi, alpha1, alphasamp, sms, phidetav, phim;
  float phi2det, val1, val2, nodet, scancheck;
  int iLength, i, nzell;
  pMotor sa;
  HistInt *lData = NULL;
  long lVal;
  pCounter pCount;

  /* create filename */
  self->pFile = makeFilename(pServ->pSics, pCon);
  if (!self->pFile) {
    SCWrite(pCon, "ERROR: Extra severe: failed to create data file name",
            eError);
    return;
  }
  /* create a Nexus file */
  NXopen(self->pFile, NXACC_CREATE5, &hfil);
  if (!hfil) {
    SCWrite(pCon, "ERROR: cannot create data file ", eError);
    return;
  }
  /* tell Uwe User what we are doing */
  pVar = NULL;
  pVar = FindVariable(pServ->pSics, "scancheck");
  if (pVar) {
    VarGetFloat(pVar, &scancheck);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  if (scancheck == 0) {
    snprintf(pBueffel,255, "Writing %s ......", self->pFile);
    SCWrite(pCon, pBueffel, eLog);
  }


  /* write globals */
  SNXSPutGlobals(hfil, self->pFile, "POLDI", pCon);

  /* open nxdict */
  status = NXDinitfromfile(self->dictfile, &hdict);
  if (status != NX_OK) {
    sprintf(pBueffel, "ERROR: failed to open dictionary file %s",
            self->dictfile);
    SCWrite(pCon, pBueffel, eError);
    SCWrite(pCon, "ERROR: Aborting data file writing", eError);
    SCWrite(pCon, "ERROR: This is a SERIOUS problem!", eError);
    SCWrite(pCon, "ERROR: DATA NOT WRITTEN", eError);
    NXclose(&hfil);
    return;
  }


  writePolterdiGlobal(hfil, hdict, pCon);

  writeChopper(hfil, hdict, pCon);

  writeDiaphragm1(hfil, hdict, pCon);

  writeDiaphragm2(hfil, hdict, pCon);

  writeCollimator(hfil, hdict, pCon);

  writeSample(hfil, hdict, pCon);

  /*
     write time binning
   */

  fTime = GetHistTimeBin(self->pHist, &iLength);
  fTime2 = (float *) malloc(iLength * sizeof(float));
  if (fTime2) {
    for (i = 0; i < iLength; i++) {
      fTime2[i] = fTime[i] / 2.;
    }
    if(iLength > 2){
      sprintf(pBueffel, "%d", iLength);
    } else {
      sprintf(pBueffel, "%d", 1);
    }
    NXDupdate(hdict, "timebin", pBueffel);
    NXDputalias(hfil, hdict, "dtime", fTime2);
    free(fTime2);
  } else {
    SCWrite(pCon, "ERROR: out of memory while writing time binning",
            eError);
  }

  /*
     theta calculation
   */
  det_radius = (float) DETRADIUS;
  pVar = FindVariable(pServ->pSics, "det_size");
  if (pVar) {
    VarGetFloat(pVar, &det_size);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  pVar = NULL;
  pVar = FindVariable(pServ->pSics, "nodet");
  if (pVar) {
    VarGetFloat(pVar, &nodet);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  pVar = NULL;
  nzell = (int) nodet;

  pVar = FindVariable(pServ->pSics, "x0_det");
  if (pVar) {
    VarGetFloat(pVar, &x0det);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  pVar = NULL;
  pVar = FindVariable(pServ->pSics, "y0_det");
  if (pVar) {
    VarGetFloat(pVar, &y0det);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  pVar = NULL;
  pVar = FindVariable(pServ->pSics, "twotheta");
  if (pVar) {
    VarGetFloat(pVar, &twothet);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }

  pi = 3.1415926536;
  /* transformation to radient */
  twothet = twothet * pi / 180;
  if (x0det < 0) {
    alpha1 = atan(y0det / x0det);
  }
  if (x0det > 0) {
    alpha1 = pi + atan(y0det / x0det);
  }
  alphasamp = pi + alpha1 - twothet;
  sms = sqrt(x0det * x0det + y0det * y0det);
  phidetav =
      pi - alphasamp - asin(sms / det_radius * sin(alphasamp)) + alpha1;
  phim = atan(y0det / x0det);
  if (phim < 0) {
    phim = pi + phim;
  }
  for (i = 0; i <= nzell; i++) {
    phi2det =
        phidetav + (i - 0.5 * (nzell - 1.0)) * det_size / (det_radius);
    val1 = det_radius * sin(phi2det) - sms * sin(phim);
    val2 = det_radius * cos(phi2det) - sms * cos(phim);
    fTheta0[i] = atan(val1 / val2);
    if (fTheta0[i] < 0) {
      fTheta0[i] = pi + fTheta0[i];
    }
    /* transformation to degree */
    fTheta0[i] = fTheta0[i] * 180 / pi;
  }
  for (i = 0; i <= nzell; i++) {
    fTheta[i] = fTheta0[nzell - i];
  }
  NXDputalias(hfil, hdict, "dtheta", fTheta);
  NXDputalias(hfil, hdict, "detector_radius", &det_radius);
  NXDputalias(hfil, hdict, "cell_size", &det_size);
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "ddist",
                  "detectordist");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "sangle",
                  "scatt_angle");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "detx0", "x0_det");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "dety0", "y0_det");
  SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "theta", "twotheta");
  SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "cnhepress","he_pressure");
  /*
     write Histogram
   */
  lData = GetHistogramPointer(self->pHist, pCon);
  if (lData) {
    NXDputalias(hfil, hdict, "dcounts", lData);
  } else {
    SCWrite(pCon, "ERROR: failed to get histogram data", eError);
  }

  /*
     write counting data
   */
  pCount = (pCounter)FindCommandData(pServ->pSics,"counter","SingleCounter");
  if(pCount){
	  fVal = GetCountTime(pCount, pCon);
	  NXDputalias(hfil, hdict, "cntime", &fVal);
	  lVal = GetMonitor(pCount, 1, pCon);
	  NXDputalias(hfil, hdict, "cnmon1", &lVal);
	  lVal = GetMonitor(pCount, 2, pCon);
	  NXDputalias(hfil, hdict, "cnmon3", &lVal);
	  lVal = GetMonitor(pCount, 3, pCon);
	  NXDputalias(hfil, hdict, "cnmon4", &lVal);
	  eMode = GetCounterMode(pCount);
	  if (eMode == eTimer) {
		  strcpy(pBueffel, "timer");
	  } else {
		  strcpy(pBueffel, "monitor");
	  }
	  NXDputalias(hfil, hdict, "cnmode", pBueffel);
	  fVal = GetCounterPreset(pCount);
	  NXDputalias(hfil, hdict, "cnpreset", &fVal);
  } else {
	  SCWrite(pCon,"ERROR: counter not found writing data file", eLogError);
  }

  /* close everything */
  NXclose(&hfil);
  NXDclose(hdict, NULL);
  self->iNew = 0;
}

/*---------------------------------------------------------------------------*/

static void PoldiUpdate(pPolterdi self, SConnection * pCon)
{
  char pBueffel[256];
  NXhandle hfil = NULL;
  NXdict hdict = NULL;
  int status;
  const float *fTime = NULL;
  CounterMode eMode;
  float *fTime2 = NULL, fTheta[801], fVal;
  pSicsVariable pVar = NULL;
  float det_radius, det_size, x0det, y0det, twothet;
  float pi, alpha1, alphasamp, sms, phidetav, phim;
  float phi2det, val1, val2, nodet, scancheck;
  int iLength, i, nzell;
  pMotor sa;
  HistInt *lData = NULL;
  long lVal;
  time_t zeit;
  pCounter pCount = NULL;

  /* open everything again */
  status = NXopen(self->pFile, NXACC_RDWR, &hfil);
  if (status != NX_OK) {
    SCWrite(pCon, "ERROR: cannot reopen data file ", eError);
    return;
  }
  status = NXDinitfromfile(self->dictfile, &hdict);
  if (status != NX_OK) {
    sprintf(pBueffel, "ERROR: failed to open dictionary file %s",
            self->dictfile);
    SCWrite(pCon, pBueffel, eError);
    SCWrite(pCon, "ERROR: Aborting data file writing", eError);
    SCWrite(pCon, "ERROR: This is a SERIOUS problem!", eError);
    SCWrite(pCon, "ERROR: DATA NOT WRITTEN", eError);
    NXclose(&hfil);
    return;
  }

  /* tell the user that something is happening */
  pVar = NULL;
  pVar = FindVariable(pServ->pSics, "scancheck");
  if (pVar) {
    VarGetFloat(pVar, &scancheck);
  } else {
    SCWrite(pCon, "ERROR: Command not found!", eError);
    return;
  }
  if (scancheck == 0) {
    time(&zeit);
    snprintf(pBueffel,255, "Updating %s on %s ", self->pFile,
            asctime(localtime(&zeit)));
    SCWrite(pCon, pBueffel, eWarning);
  }
  SNXFormatTime(pBueffel, sizeof(pBueffel));
  NXDputalias(hfil, hdict, "eend", pBueffel);


  /*
     write time binning
   */

  /*
  fTime = GetHistTimeBin(self->pHist, &iLength);
  fTime2 = (float *) malloc(iLength * sizeof(float));
  if (fTime2) {
    for (i = 0; i < iLength; i++) {
      fTime2[i] = fTime[i] / 2.;
    }
    sprintf(pBueffel, "%d", iLength);
    NXDupdate(hdict, "timebin", pBueffel);
    NXDputalias(hfil, hdict, "dtime", fTime2);
    free(fTime2);
  } else {
    SCWrite(pCon, "ERROR: out of memory while writing time binning",
            eError);
  }
*/

  /*
     write Histogram
   */

  lData = GetHistogramPointer(self->pHist, pCon);
  if (lData) {
    NXDputalias(hfil, hdict, "dcounts", lData);
  } else {
    SCWrite(pCon, "ERROR: failed to get histogram data", eError);
  }

  /*
     write counting data
   */
  pCount = (pCounter)FindCommandData(pServ->pSics,"counter","SingleCounter");
  if(pCount){
	  fVal = GetCountTime(pCount, pCon);
	  NXDputalias(hfil, hdict, "cntime", &fVal);
	  lVal = GetMonitor(pCount, 1, pCon);
	  NXDputalias(hfil, hdict, "cnmon1", &lVal);
	  lVal = GetMonitor(pCount, 4, pCon);
	  NXDputalias(hfil, hdict, "cnprot", &lVal);
	  lVal = GetMonitor(pCount, 2, pCon);
	  NXDputalias(hfil, hdict, "cnmon3", &lVal);
	  lVal = GetMonitor(pCount, 3, pCon);
	  NXDputalias(hfil, hdict, "cnmon4", &lVal);
	  eMode = GetCounterMode(pCount);
	  if (eMode == eTimer) {
		  strcpy(pBueffel, "timer");
	  } else {
		  strcpy(pBueffel, "monitor");
	  }
	  NXDputalias(hfil, hdict, "cnmode", pBueffel);
	  fVal = GetCounterPreset(pCount);
	  NXDputalias(hfil, hdict, "cnpreset", &fVal);
  } else {
	  SCWrite(pCon,"ERROR: counter not found writing data file", eLogError);
  }


  /* close everything */
  NXclose(&hfil);
  NXDclose(hdict, NULL);

}

/*-------------------------------------------------------------------------
  FoLink sets all the links for the NXdata vGroup. Had to be separate because
  at least one update is necessary before this can be done.
-------------------------------------------------------------------------*/

static void PoldiLink(pPolterdi self, SConnection * pCon)
{
  NXhandle hfil = NULL;
  NXdict hdict = NULL;
  int status;
  char pBueffel[512];

  /* open everything again */
  NXopen(self->pFile, NXACC_RDWR, &hfil);
  if (!self->pFile) {
    SCWrite(pCon, "ERROR: cannot reopen data file ", eError);
    return;
  }
  status = NXDinitfromfile(self->dictfile, &hdict);
  if (status != NX_OK) {
    sprintf(pBueffel, "ERROR: failed to open dictionary file %s",
            self->dictfile);
    SCWrite(pCon, pBueffel, eError);
    SCWrite(pCon, "ERROR: Aborting data file writing", eError);
    SCWrite(pCon, "ERROR: This is a SERIOUS problem!", eError);
    SCWrite(pCon, "ERROR: DATA NOT WRITTEN", eError);
    NXclose(&hfil);
    return;
  }

  NXDaliaslink(hfil, hdict, "dana", "dcounts");
  NXDaliaslink(hfil, hdict, "dana", "dtheta");
  NXDaliaslink(hfil, hdict, "dana", "dtime");

  /* close everything */
  NXclose(&hfil);
  NXDclose(hdict, NULL);

}

/*---------------------------------------------------------------------------
  This is the task function for updating the data file any now and then
  automatically
 --------------------------------------------------------------------------*/
static int PoldiTask(void *pData)
{
  pPolterdi self = NULL;
  int iWrite, iRet, ltask;

  self = (pPolterdi) pData;
  if (!self)
    return 0;

  /* figure out if we need to write */
  iWrite = 0;
  iRet = 1;
  /* first case: update intervall */
  if (time(NULL) >= self->tUpdate) {
    ltask = GetDevexecID(pServ->pExecutor);
    if (ltask > 0) {
      self->tUpdate = time(NULL) + self->iInterval;
      iWrite = 1;
      iRet = 1;
    } else {
      self->iEnd = 1;
    }
  }

  if (self->iEnd == 1) {
    self->tUpdate = 0;
    iWrite = 0;
    iRet = 0;
  }

  if (iWrite) {
    if (self->iNew) {
      PoldiStart(self, self->pCon);
      PoldiUpdate(self, self->pCon);
      PoldiLink(self, self->pCon);
    } else {
      PoldiUpdate(self, self->pCon);
    }
  }
  return iRet;
}

/*----------------------------------------------------------------------*/
static void KillPolterdi(void *pData)
{
  pPolterdi self = (pPolterdi) pData;
  if (!self)
    return;

  if (self->pDes) {
    DeleteDescriptor(self->pDes);
  }
  if (self->pFile) {
    free(self->pFile);
  }
  if (self->dictfile) {
    free(self->dictfile);
  }
  free(self);
}




/*-----------------------------------------------------------------------*/
int PolterInstall(SConnection * pCon, SicsInterp * pSics,
                  void *pData, int argc, char *argv[])
{
  pPolterdi pNew = NULL;
  pICallBack pCall = NULL;
  pDummy pDum;
  pHistMem pHist = NULL;
  commandContext comCon;

  /* configure fortify */
  /*
     iFortifyScope = Fortify_EnterScope();
     Fortify_CheckAllMemory();
   */
  if (argc < 2) {
    SCWrite(pCon,
            "ERROR: insufficient number of arguments to PolterInstall",
            eError);
    return 0;
  }
  pHist = (pHistMem) FindCommandData(pSics, HM, "HistMem");

  if (!pHist) {
    SCWrite(pCon, "ERROR: Histogram memory NOT found", eError);
    return 0;
  }

  pNew = (pPolterdi) malloc(sizeof(Polterdi));
  if (!pNew) {
    SCWrite(pCon, "ERROR: out of memory in PolterInstall", eError);
    return 0;
  }
  memset(pNew, 0, sizeof(Polterdi));
  pNew->pDes = CreateDescriptor("PoldiWrite");
  pNew->pHist = pHist;
  pNew->dictfile = strdup(argv[1]);
  pNew->iInterval = 20 * 60;
  if (!pNew->pDes || !pNew->dictfile) {
    SCWrite(pCon, "ERROR: out of memory in PolterInstall", eError);
    return 0;
  }
  /* install callbacks */
  pDum = (pDummy) pHist;
  pCall =
      (pICallBack) pDum->pDescriptor->GetInterface(pHist,
                                                   CALLBACKINTERFACE);
  if (!pCall) {
    SCWrite(pCon,
            "ERROR: no callback interface found at your histogram memory",
            eError);
    KillPolterdi(pNew);
    return 0;
  }
  strlcpy(comCon.deviceID, "internal", SCDEVIDLEN);
  RegisterCallback(pCall, COUNTSTART, Countstartcallback, pNew, NULL);
  RegisterCallback(pCall, COUNTEND, Countendcallback, pNew, NULL);

  AddCommand(pSics, "storedata", PolterAction, KillPolterdi, pNew);
  return 1;

}

/*----------------------------------------------------------------------*/
int PolterAction(SConnection * pCon, SicsInterp * pSics,
                 void *pData, int argc, char *argv[])
{
  int iRet, iVal;
  pPolterdi self = NULL;
  char pBueffel[512];

  if (argc < 2) {
    SCWrite(pCon, "ERROR: Insufficient number of arguments to StoreData",
            eError);
    return 0;
  }

  self = (pPolterdi) pData;
  assert(self);

  strtolower(argv[1]);
  if (strcmp(argv[1], "start") == 0) {
    PoldiStart(self, pCon);
    PoldiUpdate(self, pCon);
    PoldiLink(self, pCon);
    return 1;
  } else if (strcmp(argv[1], "update") == 0) {
    if ((self->iNew) || (!self->pFile)) {
      PoldiStart(self, pCon);
      PoldiUpdate(self, pCon);
      PoldiLink(self, pCon);
    } else {
      PoldiUpdate(self, pCon);
    }
    return 1;
  } else if (strcmp(argv[1], "getfile") == 0) {
    snprintf(pBueffel,511, "StoreData.file = %s", self->pFile);
    SCWrite(pCon, pBueffel, eValue);
    return 1;
  } else if (strcmp(argv[1], "interval") == 0) {
    if (argc > 2) {             /* set value */
      if (!SCMatchRights(pCon, usUser)) {
        return 0;
      }
      iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iVal);
      if (iRet != TCL_OK) {
        snprintf(pBueffel,511, "ERROR: cannot convert --> %s <-- to number ",
                argv[2]);
        SCWrite(pCon, pBueffel, eError);
        return 0;
      }
      self->iInterval = iVal * 60;      /* go to seconds from minutes */
      SCSendOK(pCon);
      return 1;
    } else {                    /* read the value */

      sprintf(pBueffel, "storedata.interval = %d", self->iInterval / 60);
      SCWrite(pCon, pBueffel, eValue);
      return 1;
    }
  }

  SCWrite(pCon, "ERROR: subcommand to StoreData not recognized", eError);
  return 0;
}
