#include <farfalla.h>
#include <eventNode.h>
#include <dream.h>
#include <cspamNode.h>
#include <BitString.h>
#include <math.h>

extern eventNode *ev;
int getCspamNibble(int SM, int channel, int hilo);

void dreamMakeCspamNodes() 
{
  union {int i[1000]; short s[2000];} data; 
  union {int i[1000]; short s[2000];} spuData; 
  cspamNode *cspamBank;
  int index[3], ierr[3]; 
  int spuIndex, spuErr;
  BitString oldCspam[3][11];
  // First check to see if there are CSPAM equips in any microvax

  dsaget_("DECO",1,30,1,index[0],ierr[0]);
  dsaget_("DECO",2,30,1,index[1],ierr[1]);
  dsaget_("DECO",3,30,1,index[2],ierr[2]);

  // If every mVax returns -1 bail 
  if ((ierr[0]!=0) && (ierr[1]!=0) && (ierr[2]!=0)) return;

  F_addChild(ev,cspamBank);	// Make the CSPAM node
  //Initialize to zero
  
  for (int i=0; i<10; i++)
  {
    cspamBank->patternHi1[i]=0;
    cspamBank->patternHi0[i]=0;
    cspamBank->patternLo1[i]=0;
    cspamBank->patternLo0[i]=0;
  }
  cspamBank->hipHitPattern=0;
  cspamBank->fmtHitPattern=0;
  cspamBank->cspamHitPattern=0;
  for (int mVax=0; mVax < 3; mVax++)
  {
    int iierr;
    if (ierr[mVax]==0)
    {
      // There is an equipment 30
      // first lets get the trigger info (in equip 32)
      dsaget_("DECO",mVax+1,32,1,spuIndex,spuErr);
      if(spuErr==0)
      {
	int serr;
	dsaget_("RAWW",1,spuIndex+2,3,spuData.i[0], serr);
	cout << hex;
	if(mVax==0)
	{
	  // FMT in bits 1 and 11 (shift none and 9)
	  // CSPAM bits in 5 and 12 (shift 4 and 10)
	  // HIP in bits 3 and 4 (word 2) (shift 2)
	  cspamBank->fmtHitPattern|=(0x1 & spuData.s[0]);
	  cspamBank->fmtHitPattern|=(0x2 & (spuData.s[0]>>9));
	  cspamBank->hipHitPattern|=(0x3 & (spuData.s[1]>>2));
	  cspamBank->cspamHitPattern|=(0x1 & (spuData.s[0]>>4));
	  cspamBank->cspamHitPattern|=(0x2 & (spuData.s[0]>>10));
	}
	if(mVax==1)
	{
	  // FMT in bits 11, 1, and 13 (shift 8, -2, and 8)
	  // CSPAM bits in 12, 5, and 14 (shift 9,1 and 9)
	  // HIP in bits 4,3 and 5 (word 2) (shift 1, -1, none)
	  cspamBank->fmtHitPattern|=(0x4 & (spuData.s[0]>>8));
	  cspamBank->fmtHitPattern|=(0x8 & (spuData.s[0]<<3));
	  cspamBank->fmtHitPattern|=(0x10 & (spuData.s[0]>>8));
	  cspamBank->hipHitPattern|=(0x4 & (spuData.s[1]>>1));
	  cspamBank->hipHitPattern|=(0x8 & (spuData.s[1]<<1));
	  cspamBank->hipHitPattern|=(0x10 & spuData.s[1]);
	  cspamBank->cspamHitPattern|=(0x4 & (spuData.s[0]>>9));
	  cspamBank->cspamHitPattern|=(0x8 & (spuData.s[0]>>1));
	  cspamBank->cspamHitPattern|=(0x10 & (spuData.s[0]>>9));
	}
	if(mVax==2)
	{
	  // FMT in bits 1 and 13 (shift -5, 6)
	  // CSPAM bits in 5 and 14 (shift -1, 7)
	  // HIP in bits 3 and 5 (word 2) (shift -3, -1)
	  cspamBank->fmtHitPattern|=(0x20 & (spuData.s[0]>>7));
	  cspamBank->fmtHitPattern|=(0x40 & (spuData.s[0]<<6));
	  cspamBank->hipHitPattern|=(0x20 & (spuData.s[1]<<1));
	  cspamBank->hipHitPattern|=(0x40 & (spuData.s[1]<<4));
	  cspamBank->cspamHitPattern|=(0x20 & (spuData.s[0]>>8));
	  cspamBank->cspamHitPattern|=(0x40 & (spuData.s[0]<<2));
	}
      }
      if(cspamBank->hipHitPattern)
      {
	cout << "MVAX " << mVax << endl;
	cout << "Cspam Node Hip   Pattern :" << hex << cspamBank->hipHitPattern << endl;
	cout << "Cspam Node Cspam Pattern :" << cspamBank->cspamHitPattern << endl;
	cout << "SPR Word 1               :" << spuData.s[0] << endl;
	cout << "SPR Word 2               :" << spuData.s[1] << dec << endl;
      }
      int length = 11;
      if(mVax==1)length=5;
      dsaget_("RAWW",1,index[mVax]+2,length,data.i[0],iierr);
      for(i=0 ; i< length ; i++)
	oldCspam[mVax][i]=shorttoBitString(data.s[i]);
    }
  }  // for loop

  // IMPORTANT NOTE
  // THis part of the code stuffs the bits into bitStrings defined
  // in the cspamNode and relies on the output routine to convert this
  // data into shorts.  Do NOT try to call cspamNode's print routine, which
  // will destroy these bitStrings by replacing them with the (uninitialized)
  // shorts.  print is currently only intended for after a read from disk.
  
  for (int SM=0; SM<10; SM++)
  {
    for (int channel=0; channel < 12; channel+=2)
    {
      int loNibble=getCspamNibble(SM,channel/2,0);
      int hiNibble=getCspamNibble(SM,channel/2,1);

      if(hiNibble>=0 && hiNibble<=43 && SM<6)
      { // regular data
	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4))
	  cspamBank->patternHi1[SM].set(channel+1);
	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+1))
	  cspamBank->patternHi0[SM].set(channel+1);
	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+2))
	  cspamBank->patternHi1[SM].set(channel);
	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+3))
	  cspamBank->patternHi0[SM].set(channel);
      }
      if(loNibble>=0 && loNibble<=43 && SM<6)
      { // regular data
	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4))
	  cspamBank->patternLo1[SM].set(channel+1);
	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+1))
	  cspamBank->patternLo0[SM].set(channel+1);
	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+2))
	  cspamBank->patternLo1[SM].set(channel);
	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+3))
	  cspamBank->patternLo0[SM].set(channel);
      }

      if(hiNibble>=0 && hiNibble<=43 && SM>=6)
      { // inter-microvax data
	// I apologize for being needlessly complicated
	// ((SM-6)/2)*2 obeys the following map:
	// 6->0
	// 7->0
	// 8->2
	// 9->2
	if(oldCspam[((SM-6)/2)*2][hiNibble/4].test((hiNibble%4)*4))
	  cspamBank->patternHi1[SM].set(channel+1);
	if(oldCspam[((SM-6)/2)*2][hiNibble/4].test((hiNibble%4)*4+1))
	  cspamBank->patternHi0[SM].set(channel+1);
	if(oldCspam[((SM-6)/2)*2][hiNibble/4].test((hiNibble%4)*4+2))
	  cspamBank->patternHi1[SM].set(channel);
	if(oldCspam[((SM-6)/2)*2][hiNibble/4].test((hiNibble%4)*4+3))
	  cspamBank->patternHi0[SM].set(channel);
      }
      if(loNibble>=0 && loNibble<=43 && SM>=6)
      { // inter-microvax data
	if(oldCspam[((SM-6)/2)*2][loNibble/4].test((loNibble%4)*4))
	  cspamBank->patternLo1[SM].set(channel+1);
	if(oldCspam[((SM-6)/2)*2][loNibble/4].test((loNibble%4)*4+1))
	  cspamBank->patternLo0[SM].set(channel+1);
	if(oldCspam[((SM-6)/2)*2][loNibble/4].test((loNibble%4)*4+2))
	  cspamBank->patternLo1[SM].set(channel);
	if(oldCspam[((SM-6)/2)*2][loNibble/4].test((loNibble%4)*4+3))
	  cspamBank->patternLo0[SM].set(channel);
      }
//      // swap for Imvax SM3 B,C (hip) and t (cspam)
//      if((SM==7)&&(channel==1 || channel==3))
//      {
//	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+3))
//	// SM3 inter-uVax for 3B,C
//	  cspamBank->patternHi1[SM].set(channel+1);
//	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+2))
//	  cspamBank->patternHi0[SM].set(channel+1);
//	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4+1))
//	  cspamBank->patternHi1[SM].set(channel);
//	if(oldCspam[SM/2][hiNibble/4].test((hiNibble%4)*4))
//	  cspamBank->patternHi0[SM].set(channel);
//     }	  
//      if( SM==7 && channel==4)
//      {
//	// SM3 inter-uVax for 3t
//	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+3))
//	  cspamBank->patternLo1[SM].set(channel+1);
//	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+2))
//	  cspamBank->patternLo0[SM].set(channel+1);
//	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4+1))
//	  cspamBank->patternLo1[SM].set(channel);
//	if(oldCspam[SM/2][loNibble/4].test((loNibble%4)*4))
//	  cspamBank->patternLo0[SM].set(channel);
//     }

    }
  }
}

// There is a pattern, which you might be able to ween
// from the tables below.  But for readability a lookup array is best.
// pass getCspamBit the SM(0-5) and channel(0=b,1=B,2=c, etc for bctwen)
// The number returned is actually the nibble in the cspam data where the
// requested info lives.  The first two bits in each nibble are 1 and 0
// of the upper part of the plane data, the last two are 1 and 0 of the 
// lower plane data. (with three exceptions)

int getCspamNibble(int SM, int channel, int hilo)
{                                     
  int loCspamLookup[10][6] =
  {                         
   { 24, 26, 32, 28, 30, 20}
  ,{ 25, 27, 33, 29, 31, -1}
  ,{  0,  2,  8,  4,  6, -1}
  ,{  1,  3,  9,  5,  7, -1}
  ,{  0,  2,  8,  4,  6, -1}
  ,{  1,  3,  9,  5,  7, 20}
  ,{  0,  2,  8,  4,  6, -1}
  ,{  1,  3,  9,  5,  7, -1}
  ,{ 33, 34, 41, 37, 39, -1}
  ,{ 32, 33, 40, 36, 38, -1}};

  int hiCspamLookup[10][6] =
  {
  { 36, 38, 34, 40, 42, 22}
  ,{ 37, 39, 35, 41, 43, -1}
  ,{ 12, 14, 10, 16, 18, -1}
  ,{ 13, 15, 11, 17, 19, -1}
  ,{ 12, 14, 10, 16, 18, -1}
  ,{ 13, 15, 11, 17, 19, 22}
  ,{ 12, 14, 10, 16, 18, -1}
  ,{ 13, 15, 11, 17, 19, -1}
  ,{ 25, 27, 43, 29, 31, -1}
  ,{ 24, 26, 42, 28, 30, -1}};

  if (SM<0 || SM>9 || channel <0 || channel>5) return -1;
  // SM6 is SM2 interMvax data, SM7 is for 3, etc.
  
  if (hilo==0) return loCspamLookup[SM][channel];
  if (hilo==1) return hiCspamLookup[SM][channel];

  return -1;
}

// After coming back to this program after I while I was totally
// confused.  This table of cspam data is helpful (I got it from Erik)
//
// word|  MV1   |  MV2   |  MV3
// ====|========|========|========
//  0  |2b3b2c3c|3b4b3c4c|5b6b5c6c  note: each word is I*2
//  1  |2w3w2e3e|3w4w3e4e|5w6w5e6e        each I*2 is 4 nibbles
//  2  |2t3t2T3T|3t4t3T4T|5t6t5T6T
//  3  |2B3B2C3C|3B4B3C4C|5B6B5C6C
//  4  |2W3W2E3E|3W4W3E4E|5W6W5E6E
//  5  |1n--1N--|--------|6s--6S--  
//  6  |1b2b1c2c|--------|5B4B5C4C  
//  7  |1w2w1e2e|--------|5W4W5E4E
//  8  |1t2t1T2T|--------|5b4b5c4c
//  9  |1B2B1C2C|--------|5w4w5e4e
// 10  |1W2W1E2E|--------|5t4t5T4T
//
//
// 
// so from the table above, 4C info is stored in nibble 15 in mVax2
// For Inter SM data, where 4 and 5 are registered together, 
// 4C info is stored in nible 27 on mVax3.
