// This Class knows how to map different the various ways of referring to
// each tank.  It is a useful and simple class, but users should be
// sure to understand how it works.
//
// The idea is you can initialize it to any kind of trigger numbering scheme
// including:
//                Example
// Tank Name      1N01-0
// Erp Box        537
// Wfd input      322,2   (wfdaddress, disc-bit)
// tohm channel   3,14    (word,bit)
// lip channel    3,14    (word,bit)
// cspam patch    3,14    (word,bit)
// 
// Note that there is NOT a one-one correspondence for the different ways
// to specify a channel.  The only unique way to specifiy a box is by the
// 6 character name, so all mapping is defined in terms of the name.
// This means that the initialized object is converted to a name.  Then this
// name is converted to all of the other types.
//
// when you initialize the object you do this by something like
//
// tankMap tank(322,2, WFD_TANK);
//
// I am forcing you to include as much info as necessary to resolve a tank
//
// When a mapping is ambiguous, the lowest in a group is returned.
// The exception to this is that the object you initialize with is never
// regenerated by another map.
//
// Here is how to initialize (almost everything in sight is a short)
//
// name
// tankMap myTank("1N01-0",NAME_TANK);
//
// erp
// tankMap myTank(calmodbox, end, ERP_TANK);
//
// lip, cit
// tankMap myTank(SM,word,bit, LIP_TANK);  // or CIT_TANK for cit
//
// wfd
// tankMap myTank(channel, bit, WFD_TANK);
//
// To extract use the member functions
// name()
// wfdAddress()
// wfdBit()
// erp()
// side()
// sm()
// citWord()
// citBit()
// lipWord()
// lipBit()
//
// I decided to exclude the cspam for now, because its format introduces
// more ambiguities than this class can keep straight.  I have not deccided
// how to deal with the INTER-MVAX triggers.

#include <strstream.h>
#include <String.h>

enum {ERP_TANK, WFD_TANK, CIT_TANK, LIP_TANK, NAME_TANK};

static String smLookup[6]= {"1","2","3","4","5","6"};
static String endLookup[2]= {"-0","-1"};
static String stringNum[19]= {"00","01","02","03","04",
			      "05,""06","07","08","09",
			      "10","11","12","13","14",
			      "15","16","17","18"};

static String nameLookup[99]={"B01","B02","B03","B04",   //01-16
			      "B05","B06","B07","B08",   
			      "B09","B10","B11","B12",
			      "B13","B14","B15","B16",
			      "C01","C02","C03","C04",   //17-32
			      "C05","C06","C07","C08",
			      "C09","C10","C11","C12",
			      "C13","C14","C15","C16",
			      "W01","W02","W03","W04",   //33-39
			      "W05","W06","W07",
			      "E01","E02","E03","E04",   //40-46
			      "E05","E06","E07",
			      "N01","N02","N03","N04",   //47-53
			      "N05","N06","N07",
			      "T01","T02","T03","T04",   //54-70
			      "T05","T06","T07","T08",
			      "T09","T10","T11","T12",
			      "T13","T14","T15","T16",
			      "T17",
			      "W08","W09","W10","W11",   //71-77
			      "W12","W13","W14",
			      "E08","E09","E10","E11",   //78-84
			      "E12","E13","E14",         
			      "NON","NON","NON","NON",   //85-99
			      "NON","NON","NON","NON",
			      "NON","NON","NON","FKn",
			      "FKW","BAR","FKe"};

static int wfdLookup[100]={0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,//0-8
			   0x04,0x06,0x04,0x06,0x04,0x06,0x04,0x06, //9-16
			   0x08,0x0a,0x08,0x0a,0x08,0x0a,0x08,0x0a, //17-24
			   0x0c,0x0e,0x0c,0x0e,0x0c,0x0e,0x0c,0x0e, //25-32
			   0x10,0x12,0x10,0x12,0x10,0x12,0x10,0x14, //32-40
			   0x16,0x14,0x16,0x14,0x16,0x14,0x28,0x2a, //41-48
			   0x28,0x2a,0x28,0x2a,0x28,0x20,0x22,0x20, //49-56
			   0x22,0x20,0x22,0x20,0x22,0x24,0x26,0x24, //57-64
			   0x26,0x24,0x26,0x24,0x26,0x1e,0x18,0x1a, //65-72
			   0x18,0x1a,0x18,0x1a,0x18,0x1c,0x1e,0x1c, //73-80
			   0x1e,0x1c,0x1e,0x1c,-1  ,-1  ,-1  ,-1  , //81-88
			   -1  ,-1  ,-1  ,-1  ,-1  ,-1  ,-1  ,-1  , //89-96
			   -1  ,-1  ,-1 };                         //97-99

static short discLookup[100]={0, 1, 1, 2, 2, 3, 3, 4, 4, //0-8
			      1, 1, 2, 2, 3, 3, 4, 4, //9-16
			      1, 1, 2, 2, 3, 3, 4, 4, //17-24
			      1, 1, 2, 2, 3, 3, 4, 4, //25-32
			      1, 1, 2, 2, 3, 3, 4, 1, //33-40
			      1, 2, 2, 3, 3, 4, 1, 1, //41-48
			      2, 2, 3, 3, 4, 1, 1, 2, //49-56
			      2, 3, 3, 4, 4, 1, 1, 2, //57-64
			      2, 3, 3, 4, 4, 4, 1, 1, //65-72
			      2, 2, 3, 3, 4, 1, 1, 2, //73-80
			      2, 3, 3, 4, 0, 0, 0, 0,
			      0, 0, 0, 0, 0, 0, 0, 0,
			      0, 0, 0};

class tankMap {
  
short erpBox;
short citW;
short citB;
short lipW;
short lipB;
String tankName;
short wfdAddress;
short wfdBit;
short id;
short end;
short SM;

short lipFound;
short citFound;
short erpFound;
short wfdFound;
short nameFound;

public:
tankMap(String name, short tag)  // initialize for name
{
  lipFound=0;
  citFound=0;
  erpFound=0;
  wfdFound=0;
  nameFound=1;
  tankName=name;
  id=tag;
  mapNameErp();
}
tankMap(short box, short param, short tag)
{
  id=tag;
  if (tag==ERP_TANK)
  {
    lipFound=0;
    citFound=0;
    erpFound=1;
    wfdFound=0;
    nameFound=0;
    erpBox=box;
    end=param;
  }
  if (tag==WFD_TANK)
  {
    lipFound=0;
    citFound=0;
    erpFound=0;
    wfdFound=1;
    nameFound=0;
    wfdAddress=box;
    wfdBit=param;
    mapWfdErp();
  }
}
tankMap(short superModule, short word, short bit, short side, short tag)
{
  id=tag;
  SM=superModule;
  end=side;
  if(tag==CIT_TANK)
  {
    lipFound=0;
    citFound=1;
    erpFound=0;
    wfdFound=0;
    nameFound=0;
    citW=word;
    citB=bit;
    mapCitErp();
  }
  if(tag==LIP_TANK)
  {
    lipFound=1;
    citFound=0;
    erpFound=0;
    wfdFound=0;
    nameFound=0;
    lipW=word;
    lipB=bit;
    mapLipErp();
  }
}
short wfd() {if (!wfdFound) mapErpWfd(); return wfdAddress;}
short wfdDisc() {if (!wfdFound) mapErpWfd(); return wfdBit;}
short erp() {return erpBox;}
short sm() {return erpBox/100;}
short citWord() {if (!citFound) mapErpCit(); return citW;}
short citBit() {if (!citFound) mapErpCit(); return citB;}
short lipWord() {if (!lipFound) mapErpLip(); return lipW;}
short lipBit() {if (!lipFound) mapErpLip(); return lipB;}
String name() {if (!nameFound) mapErpName();return tankName;}
short side() {return end;}

private:
void mapErpName()
{
  short erpLookup = erpBox%100;
  SM = erpBox/100;
  if(erpLookup!=0)
  {
    tankName=smLookup[SM]+nameLookup[erpLookup-1]+endLookup[end];
  }
  else
  {
    tankName=smLookup[SM]+"NON"+endLookup[end];
  }
  nameFound=1;
}

void mapNameErp()
{
  short calmodBox=0;
  for(int i=0; i<99 ; i++)
  {
    if(nameLookup[i]==tankName.at(1,3))calmodBox=i+1;
  }
  if(calmodBox==0)cout << "tankMap: mapping error:" << tankName << endl;
  int SM;
  if(tankName.at(0,1)=="1")      SM=0;
  else if(tankName.at(0,1)=="2") SM=1;
  else if(tankName.at(0,1)=="3") SM=2;
  else if(tankName.at(0,1)=="4") SM=3;
  else if(tankName.at(0,1)=="5") SM=4;
  else if(tankName.at(0,1)=="6") SM=5;
  else
  {
    cout << "tankMap: unable to map tankName to erp:" << tankName << endl;
    SM=0;
  }
  
  erpBox=SM*100+calmodBox;
  end=(tankName.at(5,1)=="1");
}

void mapErpCit()
{
  citFound=1;
  citW=-1;
  citB=-1;
  short erpModBox=erpBox%100;
  if(erpModBox>0 && erpModBox < 17)  //bottom
  {
    citW=0;
    citB=erpModBox-1;
  }
  if(erpModBox>16 && erpModBox < 33) //center
  {
    citW=1;
    citB=erpModBox-16-1;
  }
  if(erpModBox>32 && erpModBox<40)   // west lower
  {
    citW=2;
    citB=erpModBox-32-1;
  }
  if(erpModBox>39 && erpModBox<47)   // east lower
  {
    citW=2;
    citB=erpModBox-32;          // no -1 because a bit is skipped
  }
  if(erpModBox>46 && erpModBox<54)   // north lower
  {
    citW=5;
    citB=erpModBox-46-1;
  }
  if(erpModBox>53 && erpModBox<71)   // top
  {
    citW=3;
    citB=erpModBox-53-1;
  }
  if(erpModBox>70 && erpModBox<78)   // west upper
  {
    citW=4;
    citB=erpModBox-70-1;
  }
  if(erpModBox>77 && erpModBox<85)   // east
  {
    citW=4;
    citB=erpModBox-70;
  }
}

void mapCitErp()
{
  short erpModBox=-1;
  switch (citW) {
  case 0:
    erpModBox=citB+1;
    break;
  case 1:
    erpModBox=citB+17;
    break;
  case 2:
    erpModBox=citB+33;
    if(erpModBox>40)erpModBox--;
    break;
  case 3:
    erpModBox=citB+54;
    break;
  case 4:
    erpModBox=citB+71;
    if(erpModBox>78)erpModBox--;
    break;
  case 5:
    erpModBox=citB+47;
    break;
  }
  erpBox=SM*100+erpModBox;
}

void mapErpLip()
{
  lipB=-1;  // the erp has some boxes the lip doesn't know about
  lipW=-1;
  lipFound=1;
  short erpModBox=erpBox%100;
  if(erpModBox>0 && erpModBox < 17)  //bottom
  {
    lipW=2;
    lipB=erpModBox-1;
  }
  if(erpModBox>16 && erpModBox < 33) //center
  {
    lipW=1;
    lipB=erpModBox-17;
  }
  if(erpModBox>32 && erpModBox<40)   // west lower
  {
    lipW=4;
    lipB=erpModBox-33;
  }
  if(erpModBox>39 && erpModBox<47)   // east lower
  {
    lipW=3;
    lipB=erpModBox-40;
  }
  if(erpModBox>53 && erpModBox<70)   // top
  {
    lipW=0;
    lipB=erpModBox-54;
  }
  if(erpModBox>70 && erpModBox<78)   // west upper
  {
    lipW=4;
    lipB=erpModBox-71+8;
  }
  if(erpModBox>77 && erpModBox<85)   // east
  {
    lipW=3;
    lipB=erpModBox-78+8;
  }
}

void mapLipErp()
{
  erpBox=-1;
  short erpModBox=-1;
  switch (lipW) {
  case 0: //Top
    erpModBox=lipB+54;
    break;
  case 1: //Center
    erpModBox=lipB+17;
    break;
  case 2: //Bottom
    erpModBox=lipB+1;
    break;
  case 3: //East
    erpModBox=lipB+40; 
    if(lipB>7)erpModBox=lipB-8+78;
    break;
  case 4: //West
    erpModBox=lipB+33;
    if(lipB>7)erpModBox=lipB-8+71;
    break;
  }
  if(erpModBox>-1)erpBox=SM*100+erpModBox;
}

void mapErpWfd()
{
  wfdFound=1;
  short lookupNum = erpBox % 100;
  short wfdSM = erpBox/100+1;
  wfdAddress = 0xFFFF;
  wfdBit=-1;
  if (wfdLookup[lookupNum]>=0) 
  {
    wfdAddress = wfdSM*0x100 + wfdLookup[lookupNum];
    if(end)wfdAddress+=1;
    wfdBit = discLookup[lookupNum];
  }
}

void mapWfdErp()
{
  erpBox=-1;
  end=-1;
  SM=-1;
  short wfdMapTo=(wfdAddress%0x100);
  if(wfdAddress&1)wfdMapTo--;
  for(short erpTest=1; erpTest<100; erpTest++)
  {
    if(wfdLookup[erpTest] == wfdMapTo)
    {
      SM=wfdAddress / 0x100 -1;
      erpBox=SM*100;
      erpBox+=erpTest;
      erpBox+=(wfdBit-1)*2;
      // have to figure out the t17 and fake boxes by hand here
      switch (erpTest)
      {
      case 34:
	if(wfdBit==4)erpBox=98;
	break;
      case 41:
	if(wfdBit==4)erpBox=99;
	break;
      case 72:
	if(wfdBit==4)erpBox=97;
	break;
      case 48:
	if(wfdBit==4)erpBox=96;
	break;
      case 79:
	if(wfdBit==4)erpBox=70;
	break;
      }
      end=(wfdAddress & 1);
    }
    if(wfdLookup[erpTest] == wfdMapTo)break;
  }
  if(wfdBit<0 || wfdBit>4)
  {
    erpBox=-1;
    end=-1;
    SM=-1;
  }
}
};
