/*************************************************************************
 * systestmon.cxx
 * ==============
 * 
 * Description:
 * ------------ 
 *
 *
 * Author:
 * -------
 * S.Giovannella
 *
 * Creation date:
 * --------------
 * 4 August 1997
 *
 *************************************************************************/

/* ------------------------ Global Declarations ------------------------ */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <GeoVme.h>
#include <dmap.h>
#include <rockml2frame.h>
#include "raw2cele.h"

SysTestPeds PedVal[NumberOfSlots][NumberOfChannels];

/* ------------------------ Function Prototypes ------------------------ */
int ReadPeds(char *PedFile);
int CELEMaker(int *NWords, int *YBDataPoi, CELEStru *CaloEv, int *CELELen);
int DaqPoiUpk(int *DaqPoi, int *Chain, int *Crate, int *Slot, int *Chan);

/* =====================================================================
    Unpack DAQ Pointer to get chain, crate, slot and channel number
   ===================================================================== */
int DaqPoiUpk(int *DaqPoi, int *Chain, int *Crate, int *Slot, int *Chan)
{
  int ChainMax = 1;
  int CratePerChain =  8;
  int BoardPerCrate = 16;
  int ChanPerBoard  = 30;
  int ChanPerCrate, Pointer;
  int CrateNum, SlotNum, ChanNum;

  Pointer = *DaqPoi;
  ChanPerCrate = BoardPerCrate*ChanPerBoard;
  CrateNum = (Pointer-1)/ChanPerCrate + 1;
  SlotNum  = (Pointer-1-(CrateNum-1)*ChanPerCrate) / ChanPerBoard;
  ChanNum  =  Pointer-1-(CrateNum-1)*ChanPerCrate-ChanPerBoard*SlotNum;

  *Chain = ChainMax;
  *Crate = CrateNum;
  *Slot  = SlotNum;
  *Chan  = ChanNum;

  return 0;
}

/* =====================================================================
    Read PEDs value from "pedfile"
   ===================================================================== */
int ReadPeds(char *PedFile)
{
  int   ILoop, Status;
  int   SerNum, DaqPoi;
  int   Chain, Crate, Slot, Chan;
  float PedValL, SigmaL, ChiSqL, PedValH, SigmaH, ChiSqH;
  FILE* UsedFile;

  printf(" ReadPeds> Opening PEDs File %s \n",PedFile);
  UsedFile = fopen(PedFile,"r");
  if( UsedFile == NULL )
    {
      printf(" ReadPeds> Failure opening PEDs file \n");
      return -1;
    }

  ILoop = 0;
  while ( ILoop < 480 )
    {
      fscanf(UsedFile,"%d %d %f %f %f %f %f %f",&SerNum,&DaqPoi,
	     &PedValL,&SigmaL,&ChiSqL,&PedValH,&SigmaH,&ChiSqH);
      if ( PedValH > 4096 )
	{
	  DaqPoi  =  480 + ILoop;
	  PedValH =  PedValH - 4095;
	}

      Chain = 0;
      Crate = 0;
      Slot  = 0;
      Chan  = 0;

      Status = DaqPoiUpk(&DaqPoi,&Chain,&Crate,&Slot,&Chan);
      if ( Status != 0 )
	{
	  printf(" ReadPeds> Unable unpacking daqpointer %d \n",DaqPoi);
	  return -1;
	}

      PedVal[Slot][Chan].DPoi = DaqPoi;
      PedVal[Slot][Chan].PedL = PedValL;
      PedVal[Slot][Chan].SigL = SigmaL;
      PedVal[Slot][Chan].ChiL = ChiSqL;
      PedVal[Slot][Chan].PedH = PedValH;
      PedVal[Slot][Chan].SigH = SigmaH;
      PedVal[Slot][Chan].ChiH = ChiSqH;

      ILoop++;
    }

  fclose(UsedFile);
  return 0;
}

/* =====================================================================
    Create CELE-like event from RAW data
   ===================================================================== */
int CELEMaker(int *NWords, int *YBDataPoi, CELEStru *CaloEv, int *CELELen)
{
  int   ILoop, Status, NVal;
  int   YBosData, JLoop, *CELEAdr;
  int   FstVal, DataFlg, NumEle, CELEPoi;
  int   CELEAddress, CELE_Id, CELExist;
  float Ped, Sig, ADCVal, TDCVal;
  rockm_l2frame Frame;
  DMAP_CHAN_EL El2Cal;

  NVal = *NWords;
  FstVal = *YBDataPoi;

  NumEle = 0;
  CELEAdr = (int* )calloc(NVal,sizeof(int));

  for ( ILoop=0; ILoop<NVal; ILoop++ )
    {
      YBosData = (unsigned int) (YBDataPoi[ILoop]); 
      rockm_l2frame_raw2l2frame(YBosData,Frame);
      Frame.chan &= 31;
      if (Frame.chain == 0 ) Frame.chain = 1;
      Status = 
	dmap_get(Frame.chain,Frame.crate,Frame.slot,Frame.chan,&El2Cal);

      if ( Status != DMAP_ERROR_OK )
	{
	  printf("CELEMaker> Wrong DMAP association \n");
	  return -1;
	}
      else
	{
	  DataFlg = 0;
	  ADCVal = 0.;
	  TDCVal = 0.;
	  switch ( El2Cal.btype )
	    {
	    case DMAP_BTYPE_CALADC:
	      if ( Frame.res == 0 )
		{
		  Ped = PedVal[Frame.slot][Frame.chan].PedL;
		  Sig = PedVal[Frame.slot][Frame.chan].SigL;
		}
	      else
		{
		  Ped = PedVal[Frame.slot][Frame.chan].PedH;
		  Sig = PedVal[Frame.slot][Frame.chan].SigH;
		}
	      if ( Sig > 20. ) Sig=20.;
	      ADCVal = Frame.data - Ped;
	      if ( abs(ADCVal) > 3*Sig ) DataFlg = 1;
	      break;
	    case DMAP_BTYPE_CALTDC:
	      if ( Frame.data < 4095 ) DataFlg = 1;
              TDCVal = Frame.data;
	      break;
	    default:
	      printf("CELEMaker> Invalid BTYPE for CALR %d \n",El2Cal.btype);
	      return 0;
	    }
	}

      if( DataFlg==1 )
	{
	  CELE_Id  = 0;
	  CELExist = 0;
	  CELEAddress = El2Cal.data.cal.detector    | 
	                El2Cal.data.cal.module << 8 | 
	                El2Cal.data.cal.plane  <<16 | 
	                El2Cal.data.cal.column <<24;

	  for ( JLoop=0; JLoop<NumEle; JLoop++ )
	    {
	      if ( CELEAdr[JLoop] == CELEAddress )
		{
		  CELExist = 1;
		  CELE_Id  = JLoop;
		}
	    }

	  if ( CELExist != 1 )
	    {
	      CELEPoi = NumEle;
	      CELEAdr[CELEPoi] = CELEAddress;
	      CaloEv[CELEPoi].Det = El2Cal.data.cal.detector;
	      CaloEv[CELEPoi].Wed = El2Cal.data.cal.module;
	      CaloEv[CELEPoi].Col = El2Cal.data.cal.column;
	      CaloEv[CELEPoi].Pla = El2Cal.data.cal.plane;
	      NumEle = NumEle + 1;
	    }
	  else
	    CELEPoi = CELE_Id;

	  switch ( El2Cal.btype )
	    {
	    case DMAP_BTYPE_CALADC:
	      if ( El2Cal.data.cal.side == 1 ) CaloEv[CELEPoi].Ea = ADCVal;
	      if ( El2Cal.data.cal.side == 2 ) CaloEv[CELEPoi].Eb = ADCVal;
	      break;
	    case DMAP_BTYPE_CALTDC:
	      if ( El2Cal.data.cal.side == 1 ) CaloEv[CELEPoi].Ta = TDCVal;
	      if ( El2Cal.data.cal.side == 2 ) CaloEv[CELEPoi].Tb = TDCVal;
	      break;
	    default: ;
	    }
	}

    }

  *CELELen = NumEle;

  free (CELEAdr);
  return 0;
}