// stopNode.h
// This is v2 of the farfalla Stop Node written by Chris Orth
// It contains all of the information of MACRO equipment 40
// 
// v1 had words in a different order from the data, which proved
//    to be kind of troublesome when I switched over to single
//    arrays. 
// Trigger face times are accessible through the variable
//    trigTime[SM][int]
// where int can be one of the following:
//    STOP_TOHM=0;
//    STOP_ERP=1;
//    STOP_STM=2;
//    STOP_FMT=3;
//    STOP_CSPAM=4;
//    STOP_LIP=5;
//    STOP_ISTOP=6;
//    STOP_HIP=7;
//
// these variables are declared in this header as static to reduce
// the chance of conflict with other variables in your code
//
// Similarly, the tohm Face times are as follows:
//    faceTime[SM][int]
//    here, int can be:
//    STOP_CENTER=0;
//    STOP_BOTTOM=1;
//    STOP_WEST=2;
//    STOP_EAST=3;
//    STOP_NORTH=4;
//    STOP_TOP=5;
//    STOP_SMPLUS=6;
//    STOP_SMMINUS=7;
//
// The trigger and tohm registers are accessible through
//    trigRegister[SM]
//    tohmRegister[SM]
//
// Inline functions:
// 
//    print = the usual, but it tries to use the dash print level
//            to do this, set stopNode->printLevel=dash_pri_lev()
//            in the calling routine
//
//    smTest = returns 1 if that sm has any trigger times, 0 otherwise
//

#include <BitString.h>
#include <iomanip.h>
#include <String.h>

// trigger aliases, use these to access specific timing
//   info in the stoptime[SM][TRIGALIAS] arrays

// Trigger Word aliases
static int STOP_TOHM=0;
static int STOP_ERP=1;
static int STOP_STM=2;
static int STOP_FMT=3;
static int STOP_CSPAM=4;
static int STOP_LIP=5;
static int STOP_ISTOP=6;
static int STOP_HIP=7;
static String STOP_TRIG_NAME[8];

// Tohm Face Word Aliases
static int STOP_CENTER=0;
static int STOP_BOTTOM=1;
static int STOP_WEST=2;
static int STOP_EAST=3;
static int STOP_NORTH=4;
static int STOP_TOP=5;
static int STOP_SMMINUS=6;
static int STOP_SMPLUS=7;

static String STOP_FACE_NAME[8];
// Tohm Face Register bit aliases
static const int STOP_COINC_BIT=0;
static const int STOP_CENTER_BIT=1;
static const int STOP_BOTTOM_BIT=2;
static const int STOP_WEST_BIT=3;
static const int STOP_EAST_BIT=4;
static const int STOP_NORTH_BIT=5;
static const int STOP_TOP_BIT=6;
static const int STOP_SMMINUS_BIT=7;
static const int STOP_SMPLUS_BIT=8;
static const int STOP_SMMINUS_COINC_BIT=9;
static const int STOP_SMPLUS_COINC_BIT=10;
static const int STOP_JUNK_I_BIT=11;
static const int STOP_JUNK_II_BIT=12;
static const int STOP_JUNK_III_BIT=13;
static const int STOP_JUNK_IV_BIT=14;
static const int STOP_JUNK_V_BIT=15;

static String STOP_FACE_BIT_NAME[16];

// Trigger Register Aliases
static const int STOP_TOHM_BIT=0;
static const int STOP_ERP_BIT=1;
static const int STOP_STM_BIT=2;
static const int STOP_FMT_BIT=3;
static const int STOP_CSPAM_BIT=4;
static const int STOP_LIP_BIT=5;
static const int STOP_ISTOP_BIT=6;
static const int STOP_HIP_BIT=7;
static const int STOP_ERP_CHK_BIT=8;
static const int STOP_STM_CHK_BIT=9;
static const int STOP_TOHM_CHK_BIT=10;
static const int STOP_FMT_CHK_BIT=11;
static const int STOP_CSPAM_CHK_BIT=12;
static const int STOP_LIP_CHK_BIT=13;
static const int STOP_ISTOP_CHK_BIT=14;
static const int STOP_HIP_CHK_BIT=15;
static String STOP_TRIG_BIT_NAME[16];

// These overflow values *may* change from run to run
// If/when they are more stable, these params may
//   be useful for time-based searches
static const int TRIG_OVERFLOW[6]=
{ 10016, 10000, 10016, 10000, 10016, 10016};
static const int TOHM_OVERFLOW[6]=
{ 10000, 10000, 10016, 10002,  9744, 10002};

static F_NodeType stopType = "STOP";
class stopNode : public F_Node {

public:

  stopNode() { type = stopType; version = 2; fillArrayNames();}
  // Time info for triggers
  unsigned char version; 
  unsigned short trigTime[6][8];
  unsigned short faceTime[6][8];
  unsigned short trigRegister[6]; //bitpattern of what triggered the StopMaster
  unsigned short tohmRegister[6]; //bitpattern of the SMT face triggers.

  virtual inline void fillArrayNames()
  {
    // I decided to fill these here, because I expect that the stop
    // master manual is wrong about the bit orders, and it will be
    // very easy this way to simply change the value of the STOP*
    // array indices.  I learned the hard way that these cannot go
    // in the main body of the class because they are not interpretted
    // as initializations, but as redeclarations.

    // trigger names
    STOP_TRIG_NAME[STOP_TOHM]="TOHM ";
    STOP_TRIG_NAME[STOP_ERP] ="ERP  ";
    STOP_TRIG_NAME[STOP_CSPAM]="CSPAM";
    STOP_TRIG_NAME[STOP_STM]="STM  ";
    STOP_TRIG_NAME[STOP_FMT]="FMT  ";
    STOP_TRIG_NAME[STOP_HIP]="HIP  ";
    STOP_TRIG_NAME[STOP_LIP]="LIP  ";
    STOP_TRIG_NAME[STOP_ISTOP]="ISTOP";
    
    //tohm face names
    STOP_FACE_NAME[STOP_BOTTOM] ="BOT  ";
    STOP_FACE_NAME[STOP_CENTER] ="CENT ";
    STOP_FACE_NAME[STOP_WEST]   ="WEST ";
    STOP_FACE_NAME[STOP_EAST]   ="EAST ";
    STOP_FACE_NAME[STOP_NORTH]  ="NORTH";
    STOP_FACE_NAME[STOP_TOP]    ="TOP  ";
    STOP_FACE_NAME[STOP_SMPLUS] ="SM+  ";
    STOP_FACE_NAME[STOP_SMMINUS]="SM-  ";
 
    //trigger bit names
    STOP_TRIG_BIT_NAME[STOP_TOHM_BIT]="TOHM ";
    STOP_TRIG_BIT_NAME[STOP_ERP_BIT]="ERP ";
    STOP_TRIG_BIT_NAME[STOP_STM_BIT]="STM ";
    STOP_TRIG_BIT_NAME[STOP_CSPAM_BIT]="CSPAM ";
    STOP_TRIG_BIT_NAME[STOP_FMT_BIT]="FMT ";
    STOP_TRIG_BIT_NAME[STOP_LIP_BIT]="LIP ";
    STOP_TRIG_BIT_NAME[STOP_ISTOP_BIT]="ISTOP ";
    STOP_TRIG_BIT_NAME[STOP_HIP_BIT]="HIP ";
    STOP_TRIG_BIT_NAME[STOP_ERP_CHK_BIT]="ERPCk ";
    STOP_TRIG_BIT_NAME[STOP_STM_CHK_BIT]="STMCk ";
    STOP_TRIG_BIT_NAME[STOP_TOHM_CHK_BIT]="TOHMCk ";
    STOP_TRIG_BIT_NAME[STOP_FMT_CHK_BIT]="FMTCk ";
    STOP_TRIG_BIT_NAME[STOP_CSPAM_CHK_BIT]="CSPAMCk ";
    STOP_TRIG_BIT_NAME[STOP_LIP_CHK_BIT]="LIPCk ";
    STOP_TRIG_BIT_NAME[STOP_ISTOP_CHK_BIT]="ISTOPCk ";
    STOP_TRIG_BIT_NAME[STOP_HIP_CHK_BIT]="HIPCk ";

    // face bit names
    STOP_FACE_BIT_NAME[STOP_COINC_BIT] = "COINC ";
    STOP_FACE_BIT_NAME[STOP_BOTTOM_BIT] = "BOTT ";
    STOP_FACE_BIT_NAME[STOP_CENTER_BIT] = "CENT ";
    STOP_FACE_BIT_NAME[STOP_EAST_BIT] = "EAST ";
    STOP_FACE_BIT_NAME[STOP_WEST_BIT] = "WEST ";
    STOP_FACE_BIT_NAME[STOP_NORTH_BIT] = "NORTH ";
    STOP_FACE_BIT_NAME[STOP_TOP_BIT] = "TOP ";
    STOP_FACE_BIT_NAME[STOP_SMMINUS_BIT] = "SM- ";
    STOP_FACE_BIT_NAME[STOP_SMPLUS_BIT] = "SM+ ";
    STOP_FACE_BIT_NAME[STOP_SMMINUS_COINC_BIT] = "SM-C ";
    STOP_FACE_BIT_NAME[STOP_SMPLUS_COINC_BIT] = "SM+C ";
    STOP_FACE_BIT_NAME[STOP_JUNK_I_BIT] = "JUNK1 ";
    STOP_FACE_BIT_NAME[STOP_JUNK_II_BIT] = "JUNK2 ";
    STOP_FACE_BIT_NAME[STOP_JUNK_III_BIT] = "JUNK3 ";
    STOP_FACE_BIT_NAME[STOP_JUNK_IV_BIT] = "JUNK4 ";
    STOP_FACE_BIT_NAME[STOP_JUNK_V_BIT] = "JUNK5 ";

  }
  

  // This routine tells if there is stop data for a given SM
  virtual inline int smTest(int SM)
  {
    if(SM<0 || SM>5) return 0;
    for(int trigger = 0; trigger <=7; trigger++)
      if(trigTime[SM][trigger])return 1;
    return 0;
  }
  
  virtual inline void  print(ostream& o)
  {
    static int SM;
    BitString trigBits[6]; // these contain the same info as "register"
    BitString smtBits[6];  // variables, only they are convenient bitstrings.
    for(SM=0 ; SM<6; SM++)
    {
      trigBits[SM]=shorttoBitString(trigRegister[SM]);
      smtBits[SM]=shorttoBitString(tohmRegister[SM]);
    }
    o << "Stop Master Node   version:" << (short) version << endl << endl;
    o << " Trig |   Relative Time in 100ns units" << endl; 
    o << "      |";
    for(int testSM=0; testSM<6; testSM++)
    {
      if(smTest(testSM))
	o << "   SM" << testSM+1 << "   |";
    }
    o << endl; 
    for(int triggernum=0; triggernum<8; triggernum++)
    {
      o << STOP_TRIG_NAME[triggernum] << " | ";
      for(SM=0; SM<6 ; SM++)
	if(smTest(SM))o << setw(7) << trigTime[SM][triggernum] << " | ";
      o << endl;
    }
    for(int facenum=0; facenum<8; facenum++)
    {
      o << STOP_FACE_NAME[facenum] << " | ";
      for(SM=0; SM<6 ; SM++)
	
	if(smTest(SM))o << setw(7) << faceTime[SM][facenum] << " | ";
      o << endl;
    }
    o << "=======";
    for(SM=0;SM<6;SM++)
      if(smTest(SM))o<<"==========";
    o << endl;

    for(SM=0; SM<6; SM++)
    {
      if(trigRegister[SM]!=0)o<<"SM" << SM+1 << " Trigger Bits: ";
      for(int trigbit=0; trigbit < 16; trigbit++)
	if(trigRegister[SM] & (1<<trigbit))o << STOP_TRIG_BIT_NAME[trigbit];
      if(trigRegister[SM]!=0)o << endl;
      if(tohmRegister[SM]!=0)o<<"SM" << SM+1 << " Tohm Bits: ";
      for(int tohmbit=0; tohmbit < 16; tohmbit++)
	if(tohmRegister[SM] & (1<<tohmbit))o << STOP_FACE_BIT_NAME[tohmbit];
      if(tohmRegister[SM]!=0)o << endl;
    }
  }

  virtual inline int trigBitTest(int SM,int bitnum)
  {
    if(SM<0 || SM>5 || bitnum<0 || bitnum>15)return 0; // always allow for the stupid
    return (trigRegister[SM] & (1<<bitnum));
  }
  virtual inline int tohmBitTest(int SM,int bitnum)
  {
    if(SM<0 || SM>5 || bitnum<0 || bitnum>15)return 0; // always allow for the stupid
    return (tohmRegister[SM] & (1<<bitnum));
  }

protected:
  
  virtual inline void IOData(iostream& file, F_inout choice,
			     F_length& nodeLength)
  {
    F_IORec(file,version,choice,nodeLength);
    if(version==1 || version==0)
    {
      // I goofed on the word order in v1, and this is the workaround
      cout << "Using Workaround for stop node v" << version << endl;
      STOP_TOHM=4;
      STOP_ERP=0;
      STOP_STM=5;
      STOP_FMT=2;
      STOP_CSPAM=6;
      STOP_LIP=1;
      STOP_ISTOP=7;
      STOP_HIP=3;
      STOP_CENTER=1;
      STOP_BOTTOM=0;
      STOP_WEST=3;
      STOP_EAST=4;
      STOP_NORTH=5; 
      STOP_TOP=2;
      STOP_SMPLUS=7;
      STOP_SMMINUS=6;
      fillArrayNames();
    }
    for (int SM=0; SM<6; SM++)
      {
//	cout << "writing stop node to data" << endl;
//	cout << "Erptime :" << erpTime[SM] << endl;
	for (int trigger=0; trigger<8;trigger++)
	  F_IORec(file,trigTime[SM][trigger],choice,nodeLength);
	for (int tohmface=0; tohmface<8; tohmface++)
	  F_IORec(file,faceTime[SM][tohmface],choice,nodeLength);
	F_IORec(file,trigRegister[SM],choice,nodeLength);
	F_IORec(file,tohmRegister[SM],choice,nodeLength);
      }
  }
};

inline F_Node* newStopNode() {return new stopNode;}
static F_classDeclare declareSTOP(stopType,newStopNode);
