#include <farfalla.h>
#include <dash.h>
#include <kuip.h>
#include <higz.h>

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

#include <eventNode.h>
#include <vmeWfdNode.h>

#include <fortop.h>

extern vmeWfdNode* wfdBankGet(unsigned int wfdaddress);
extern short findPeak(vmeWfdNode* wfdBank, short bit, int& bucket,
                      int START_TIME, int END_TIME);
extern eventNode *ev;

static String hexLookup[16]={"0","1","2","3","4","5","6","7",
			     "8","9","A","B","C","D","E","F"};
int StringToWfd(String tankSpec, unsigned int& wfdAdd, short& wbit, short& end);

enum { PEAK, RANGE, ALL };
enum { DISC, ONEDISC, NODISC};

static float xloc=.1,yloc=.1;
static float size=1;

static float tmin=0,tmax=0;        // global parameters for plotting
static float vmin=0,vmax=0;
static float numytics=0.,numxtics=0.;
static float VT=0,HT=0;
static int wfdChanListLength=0;
static int wfdNodeListLength=0;
static int wfdChanList[6];
static int wfdBitList[6];
static float bitMarkerMap[4]={24.0, 25.0, 26.0, 28.0};
static float bitColorMap[5]={7.0,1.0, 2.0, 3.0, 4.0};
static float bitLineMap[5]={14.0, 1.0, 3.0, 12.0, 13.0};
static vmeWfdNode* wfdNodeList[6];
static int plotMode=PEAK;
static int discMode=DISC;
static int linecolor=6;
static int boxcolor=4;

static int lcolor;
extern struct {
  float rquest[100];
} quest_;
static float xsiz,ysiz;

void plotWfdPage();

void multiPlotEvent()
{
  for (int i=0; i < ev->numChildren(vmeWfdType); i++)
  {
    vmeWfdNode* wfdBank;
    F_getChild(ev,wfdBank,i);
    if (dash_pri_lev_() == 0) 
    {
      cout << "VME Addr: " << hex << wfdBank->chanAddr << dec
	<< "( " << ((wfdBank->chanAddr - 0x1000000)>>16)  << " dec)" 
	  << "   " << wfdBank->numHits << " buckets" << endl;
    }  
  }
}
void multiPlotTalk()
{
  const float LEADING=200;    // time to plot around a peak
  const float TRAILING=1000;
  int parsedBox=0;
  int len;
  char command[80];
  
  String commandList="DUMP PEAK RANGE TRANGE BW COL ALL HELP " 
    "BCOL SIZE XLOC YLOC LABEL LCOL XTICS YTICS VT HT HARDCOPY ";
  
  kugetc_(command,len,80);
  command[len]='\0';
  String wanted = command;
  
  int idummy;
  int numArgs=kunpar_(idummy)-1;
  int processed=1;
  
  while(!(commandList.contains(wanted)) && processed<=numArgs)
  {
    //string wanted is not a command... is it a box?
    unsigned int wfdChan;
    short ends, wfdBit;
    
    if(StringToWfd(wanted,wfdChan,wfdBit,ends))
    {
      if(dash_dbg_lev_()==1)cout << "Channel " << wfdChan << " \n";
      //string was suceesfully parsed into a wfd channel
      //now add it to the plot list
      if(!parsedBox)
      {
	//initialize the wfd Arrays
	//(I did it this way to keep last plot in memory)
	wfdChanListLength=0;
	wfdNodeListLength=0;
	parsedBox=1;
      }
      for(int numSides=0; numSides<ends ; numSides++)
      {
	if(wfdChanListLength<6)
	{
	  //add the channel to the list
	  wfdChanList[wfdChanListLength]=wfdChan+numSides;
	  wfdBitList[wfdChanListLength]=wfdBit;
	  wfdChanListLength++;
	}
	else
	{
	  cout << "No room left to plot WFD Channel: "
	    << hex << wfdChan+numSides << dec << endl;
	}
      }
    }
    else
    {
      cout << "Could not map: " << wanted << " to a valid WFD tank\n"
	"or WFDPLOT command.  Skipping...\n";
    }
    
    processed++;
    if(processed<=numArgs)
    {
      kugetc_(command,len,80);
      command[len]='\0';
      wanted = command;
    }
  }
  
  // at this point all valid wfdchannels should have been parsed out
  // and stored in wfdChanList
  if(wfdChanListLength && parsedBox)
  {
    // get the addresses of the desired WFD channels in memory
    for(int numChan=0; numChan<wfdChanListLength; numChan++)
    {
      wfdNodeList[wfdNodeListLength]=wfdBankGet(wfdChanList[numChan]*0x10000);
      if(wfdNodeList[wfdNodeListLength])
      {
	//the wfdBitList and wfdChanList should match 
	//what will actually be plotted
	wfdChanList[wfdNodeListLength]=wfdChanList[numChan];
	wfdBitList[wfdNodeListLength]=wfdBitList[numChan];
	wfdNodeListLength++;
      }
      else
      {
	cout << "Sorry, WFD address " << hex << wfdChanList[numChan] << dec 
	  << " is not present in this event.\n";
      }
    }
  }
  
  while(processed<=numArgs)
  {
    if(wanted.at(0,4)=="DUMP")
    {
      if(dash_dbg_lev_()==1)cout << "dump \n";
      // dump all the requested waveforms.
      // if the user asks for more than one (s)he gets what (s)he deserves.
      for(int i=0; i<wfdNodeListLength; i++)
      {
	cout << *wfdNodeList[i] << endl;
      }
      if(!wfdNodeListLength)cout << "No valid WFD Channels to Dump\n";
    }
    else if(wanted.at(0,4)=="PEAK")
    {
      if(dash_dbg_lev_()==1)cout << "peak \n";
      // Find the optimum times and amplitudes so as to display all peaks.
      // (not hard, just keep some running mins and maxes)
      if(!wfdNodeListLength)
      {
	cout << "No valid WFD Channels to Plot\n";
	return;
      }
      int peakBucket;
      short testpattern = 1 << (wfdBitList[0]-1);
      if(wfdBitList[0]==15)testpattern=wfdBitList[0];
      findPeak(wfdNodeList[0], testpattern, peakBucket,
	       wfdNodeList[0]->time[0],
	       wfdNodeList[0]->time[wfdNodeList[0]->numHits-1]);
      vmax=10;
      if(peakBucket<0 || peakBucket>9987)
      {
	cout << "Peak not found within buffer!" << endl;
	peakBucket=0;
      }
      vmin=wfdNodeList[0]->mVolt(peakBucket, 26);
      tmin=wfdNodeList[0]->time[peakBucket]-TRAILING;
      tmax=wfdNodeList[0]->time[peakBucket]+LEADING;
      for(int i=1; i<wfdNodeListLength; i++)
      {
	float tmintemp, tmaxtemp, vmintemp;
	testpattern = 1 << (wfdBitList[i]-1);
	if(wfdBitList[i]==15)testpattern=wfdBitList[i];
	findPeak(wfdNodeList[i], testpattern, peakBucket,
		 wfdNodeList[i]->time[0],
		 wfdNodeList[i]->time[wfdNodeList[i]->numHits-1]);
	vmintemp=wfdNodeList[i]->mVolt(peakBucket, 26);
	tmintemp=wfdNodeList[i]->time[peakBucket]-TRAILING;
	tmaxtemp=wfdNodeList[i]->time[peakBucket]+LEADING;
	if(vmintemp<vmin)vmin=vmintemp;
	if(tmintemp<tmin)tmin=tmintemp;
	if(tmaxtemp>tmax)tmax=tmaxtemp;
      }
      vmin*=1.1;
      vmax=-.1*vmin;
    }
    else if(wanted.at(0,4)=="RANG")
    {
      if(dash_dbg_lev_()==1)cout << "range \n";
      if(!wfdNodeListLength)
      {
	cout << "No valid WFD Channels to Plot\n";
	return;
      }
      // pop off four more parameters
      kugetr_(tmin);
      kugetr_(tmax);
      kugetr_(vmin);
      kugetr_(vmax);
      processed+=4;
      if(dash_dbg_lev_()==1)cout << tmin << " " << tmax 
	<< " " << vmin << " " << vmax << endl;

    }
    else if(wanted.at(0,4)=="TRAN")
    {
      if(dash_dbg_lev_()==1)cout << "trange \n";
      // pop off two more parameters
      kugetr_(tmin);
      kugetr_(tmax);
      processed+=2;
      //now get the best voltage ranges using the same approach as in PEAK
      if(!wfdNodeListLength)
      {
	cout << "No valid WFD Channels to Plot\n";
	return;
      }
      int peakBucket;
      short testpattern = 1 << (wfdBitList[0]-1);
      if(wfdBitList[0]==15)testpattern=wfdBitList[0];
      findPeak(wfdNodeList[0], testpattern, peakBucket,int(tmin),int(tmax));
      vmax=10;
      vmin=wfdNodeList[0]->mVolt(peakBucket, 26);
      for(int i=1; i<wfdNodeListLength; i++)
      {
	float vmintemp;
	testpattern = 1 << (wfdBitList[0]-1);
	if(wfdBitList[i]==15)testpattern=wfdBitList[i];
	findPeak(wfdNodeList[i], testpattern, peakBucket, int(tmin), int(tmax));
	vmintemp=wfdNodeList[i]->mVolt(peakBucket, 26);
	if(vmintemp<vmin)vmin=vmintemp;
      }
      vmin*=1.1;
      vmax=-.1*vmin;
    }
    else if(wanted.at(0,2)=="BW")
    {
      if(dash_dbg_lev_()==1)cout << "bw \n";
      lcolor=0;
      igset_("PLCI",1.0F,4);  // Reset all colors to black : poly-line
      igset_("FACI",1.0F,4);  // fill area
      igset_("PMCI",1.0F,4);  // poly-marker
    }
    else if(wanted.at(0,3)=="COL")
    {
      if(dash_dbg_lev_()==1)cout << "color \n";
      lcolor=1;
      return;
    }
    else if(wanted.at(0,4)=="XTIC")
    {
      kugetr_(numxtics);
      return;
    }
    else if(wanted.at(0,4)=="XLOC")
    {
      kugetr_(xloc);
      return;
    }
    else if(wanted.at(0,4)=="YLOC")
    {
      kugetr_(yloc);
      return;
    }
    else if(wanted.at(0,4)=="SIZE")
    {
      kugetr_(size);
      return;
    }
    else if(wanted.at(0,4)=="YTIC")
    {
      kugetr_(numytics);
      return;
    }
    else if(wanted.at(0,2)=="VT")
    {
      kugetr_(VT);
      return;
    }
    else if(wanted.at(0,2)=="HT")
    {
      kugetr_(HT);
      return;
    }
    else if(wanted.at(0,4)=="HARD")
    {
      if(dash_dbg_lev_()==1)cout << "hardcopy \n";
      char psname[80];
      kugets_(psname,len,80);
      psname[len]='\0';
      processed++;
      fortop_(72,psname,len);
      igmeta_(-72,-112);
      igset_("LWID",2);
      plotWfdPage();
      igset_("LWID",1);
      igmeta_(0,0);
      iclwk_(2); // I dont see what this will do -- nolty
      fortcl_(72);
      cout << "File " << psname << " created" << endl;
      return;
    }
    else if(wanted.at(0,3)=="ALL")
    {
      if(dash_dbg_lev_()==1)cout << "all \n";
      // Find the optimum times and amplitudes so as to display all peaks.
      // (not hard, just keep some running mins and maxes)
      if(!wfdNodeListLength)
      {
	cout << "No valid WFD Channels to Plot\n";
	return;
      }
      int peakBucket;
      short testpattern = 1 << (wfdBitList[0]-1);
      if(wfdBitList[0]==15)testpattern=wfdBitList[0];
      findPeak(wfdNodeList[0], testpattern, peakBucket,
	       wfdNodeList[0]->time[0],
	       wfdNodeList[0]->time[wfdNodeList[0]->numHits-1]);
      vmax=10;
      vmin=wfdNodeList[0]->mVolt(peakBucket, 26);
      tmin=wfdNodeList[0]->time[0];
      tmax=wfdNodeList[0]->time[wfdNodeList[0]->numHits-1];
      for(int i=1; i<wfdNodeListLength; i++)
      {
	float tmintemp, tmaxtemp, vmintemp;
	testpattern = 1 << (wfdBitList[i]-1);
	if(wfdBitList[i]==15)testpattern=wfdBitList[i];
	findPeak(wfdNodeList[i], testpattern, peakBucket,
		 wfdNodeList[i]->time[0],
		 wfdNodeList[i]->time[wfdNodeList[i]->numHits-1]);
	vmintemp=wfdNodeList[i]->mVolt(peakBucket, 26);
	tmintemp=wfdNodeList[i]->time[0];
	tmaxtemp=wfdNodeList[i]->time[wfdNodeList[i]->numHits-1];
	if(vmintemp<vmin)vmin=vmintemp;
	if(tmintemp<tmin)tmin=tmintemp;
	if(tmaxtemp>tmax)tmax=tmaxtemp;
      }
      vmin*=1.1;
      vmax=-.1*vmin;
    }
    else
    {
      if(dash_dbg_lev_()==1)cout << "help \n";
      if(!(wanted.at(0,4)=="HELP"))cout << wanted << " is not a valid command\n";
      cout << endl;
      cout << "WFD Farfalla/DASH Plotting Module. \n\n";
      cout << "To plot, simply list all the desired tanks (up to 6)\n";
      cout << "followed by at least one option\n";
      cout << endl;
      cout << "List each tank as:\n";
      cout << "\tAn ERP Box (implicitly asks for two wfd channels)\n";
      cout << "\tA WFD channel in HEX preceded by 0x\n";
      cout << "\tA 6 character tank name\n";
      cout << "\tA 4 character sub-name (also asks for both ends)\n";
      cout << "EXAMPLES:\n";
      cout << "TALK WFDPLOT 3T03-0 3C02-0 3B01-0 PEAK\n";
      cout << "TALK WFDPLOT 201 202 ALL\n";
      cout << "TALK WFDPLOT 3T03 3C02 3B01 TRANGE 998000 1000000\n";
      cout << "TALK WFDPLOT 0x300 0x301 RANGE 998000 1000000 10 -4000\n";
      cout << endl;
      cout << "Available Options";
      cout << "PEAK   autoplots around the peak in the channel\n";
      cout << "ALL    displays the entire waveform\n";
      cout << "RANGE  lets you specify the tmin, tmax, ymin, ymax\n";
      cout << "TRANGE lets you specify just tmin and tmax\n";
      cout << "DUMP   dumps raw waveform data\n";
      cout << "Finally, the HARDCOPY option must be sent by itself\n";
      cout << "HARDCOPY file   -generates postscript from last plot\n";
      cout << "If no option is given, the ranges from the last plot\n";
      cout << "are applied.\n";
      return;
    }
    processed++;
    if(processed<=numArgs)
    {
      kugetc_(command,len,80);
      command[len]='\0';
      wanted = command;
    }
  }
  if(wfdNodeList && (tmin || tmax) && (vmin || vmax) && parsedBox)
  {
    plotWfdPage();
    return;
  }
}

int StringToWfd(String tankSpec, unsigned int& wfdAdd, short& wbit, short& end)
{
  int len=tankSpec.length();
  if(len==6)
  {
    //it might be a name
    end=1;
    tankMap plotTank(tankSpec, NAME_TANK);
    wfdAdd=plotTank.wfd();
    wbit=plotTank.wfdDisc();
  }
  else if (len==4)
  {
    //it might be a partial name (no -0 or -1)
    end=2;
    tankMap plotTank(tankSpec+"-0", NAME_TANK);
    wfdAdd=plotTank.wfd();
    wbit=plotTank.wfdDisc();
  }
  else if (len==5 && tankSpec.at(0,2)=="0X") // try a WFD address
  {
    String hexAddress=tankSpec.at(2,3);
    int power=16*16;
    end=1;
    wbit=15;
    wfdAdd=0;
    for(int hexDigit=0; hexDigit<3; hexDigit++)
    {
      for(int hexTest=0; hexTest<16; hexTest++)
      {
	if(hexAddress.at(hexDigit,1)==hexLookup[hexTest])
	{
	  wfdAdd+=hexTest * power;
	  break;
	}
      }
      power=power/16;
    }
  }
  else if (len<=3)  // try ERP deoding
  {
    String erpString=tankSpec;
    end=2;
    int power=1;
    int erpBox=0;
    for(int decDigit=len-1; decDigit>-1; decDigit--)
    {
      for(int decTest=0; decTest<10; decTest++)
      {
	if(erpString.at(decDigit,1)==hexLookup[decTest])
	{
	  erpBox+=decTest*power;
	  break;
	}
      }
      power=power*10;
    }
    tankMap plotTank(erpBox,0,ERP_TANK);
    wfdAdd=plotTank.wfd();
    wbit=plotTank.wfdDisc();
  }
  return(wfdAdd>=0x100 && wfdAdd<=0x62b);
}

void multiPlotInit()
{
  // Look at KWTYPE to see if graphics is initialized (this assumes
  // main routine initialized KWTYPE to -1)
  int kwtype;
  dash_inquire_("KWTYPE",kwtype,6);
  if (kwtype == -1)
  {
    iginit_(0);
    igwkty_(kwtype);
    if (kwtype!=0)
    {
      igsse_(6,kwtype);
      igzset_("GZ",2);          // direct graphics to screen and to memory
    }
    dash_deposit_("KWTYPE",kwtype,6);
  }
  
  // OK, we don't know what these are but Colin uses them....
  igset_("LWID",0.F,4); // line width
  igset_("MSCF",.5F,4);
  igset_("BORD",1.F,4);
  istxfp_(0,2);
  igset_("CHHE",35.F,4); // character height
  igset_("FACI",7.F,4);  // fill area color index
  
  // Picture will be drawn in a roughly 8 1/2 x 11-shaped horizontal
  // rectangle centered vertically in the available display window
  xsiz = 9.5*2.54;
  ysiz = 7.*2.54;
  
  lcolor = 1; // Turn on color
  return;
}

void plotWfdPage()
{
  igset_("CHHE", 35.F,4);
  igset_("FAIS",0); // set fill to none

  if (lcolor)
  {
    igset_("PLCI",7.F,4);       // poly-line color index
    igset_("LTYP",1.F,4);       // line type
  }
  else igset_("LTYP",3.F,4);    // line type

  iclrwk_(0,0);
  izpict_(" ","S",1,1); // scratch old HIGZ pic
  izpict_(" ","M",1,1); // create new HIGZ pic
  igrng_(xsiz,ysiz);
  float  ntx = quest_.rquest[14-1];
  float  nty = quest_.rquest[15-1];
  float dntx = quest_.rquest[12-1];
  float dnty = quest_.rquest[13-1];
  float ymin;
  float ymax;

  // if for some reason the max and min are flipped, swap 'em
  if(tmin>tmax){float temp=tmin; tmin=tmax; tmax=temp;}
  if(vmin>vmax){float temp=vmin; vmin=vmax; vmax=temp;}

  // parameters for deciding window placement/sizes
  const float TWS=.13;    // Time window scale factor
  const float VWS=.05;    // Voltage window scale factor     
  const float YSEP=nty/200.;  // vertical separation between wfd channels
  const float TEXF=1/60.;  //fraction of window text size should be
  // The workspace will be divided into one window per waveform

  // now make a big window to put all the labels on
  isvp_(99,0.f,dntx+ntx,0.f,dnty+nty);
  iswn_(99,0.f,dntx+ntx,0.F,dnty+nty);

  for(int window=0; window<wfdNodeListLength; window++)
  {
    // set the wfd window sizes
    float twmin=(-1*tmax-TWS*(tmax-tmin))/1000.; // get everything in usec
    float twmax=(-1*tmin+TWS*(tmax-tmin))/1000.; // while were at it

    
    float vwmin=vmin-VWS*(vmax-vmin);
    float vwmax=vmax+VWS*(vmax-vmin);

    float YHEIGHT;
    // set the wfd window positions
    if(wfdNodeListLength!=1)
    {
      YHEIGHT=(nty-(wfdNodeListLength-1)*YSEP)/wfdNodeListLength;
    }
    else
    {
      YHEIGHT=.6*(nty-(wfdNodeListLength-1)*YSEP)/wfdNodeListLength;
    }
    ymin=dnty + window*YHEIGHT + (window-1)*YSEP;
    ymax=ymin + YHEIGHT;
    // clip the waveforms at the viewport
    isclip_(1);

    isvp_(100+window*100,dntx,dntx+ntx,ymin,ymax);
    iswn_(100+window*100,twmin,twmax,vwmin,vwmax);
    iselnt_(100+window*100);
    if (lcolor)
    {
      igset_("PLCI",float(boxcolor),4);       // poly-line color index
    }
    else igset_("LTYP",3.F,4);    // line type
    igbox_(-1*tmax/1000.,-1*tmin/1000.,vmin,vmax);

    // calculate the text height;
    // text height is given as a percentage of the axis

    float TEXTV=wfdNodeListLength*(vmax-vmin)*TEXF;
    float TEXTH=TEXTV;
    float TICH=.03*(vmax-vmin);
    
    if(VT!=0)TEXTV=VT;
    if(HT!=0)TEXTH=HT;

    // calculate number of tics so that labels don't crowd
    int nt1v=int((vmax-vmin)/(1.5*TEXTV));
    int nt2v=5;
    float nticsV=nt1v+100*nt2v;

    // for ease assume chars are square for horizontal labels
    int nt1h=10;
    int nt2h=10;
    float nticsH=nt2h*100+nt1h;

    // let the user overide the number of tics if he wants
    if(numxtics)nticsH=numxtics;
    if(numytics)nticsV=numytics;

    // now draw the axes
    igset_("LASI",TEXTV,4);
    igaxis_(-tmax/1000.,-tmax/1000., vmin, vmax, vmin, vmax, nticsV, "H",1);

    igset_("TMSI",TICH,4);
    igset_("LASI",TEXTH,4);
    igset_("LAOF",.05*(vmax-vmin),4);
    if(!window)
    {
      igaxis_(-tmax/1000.,-tmin/1000., vmin, vmin, -tmax/1000.,
	      -tmin/1000., nticsH, "HDS",3);
    }
    else
    {
      igaxis_(-tmax/1000.,-tmin/1000., vmin, vmin, -tmax/1000.,
	      -tmin/1000., nticsH, "HUS",3);      
    }

    // draw the labels and key
    iselnt_(99);
    tankMap wfdTank1(wfdNodeList[window]->chanAddr/0x10000,1,WFD_TANK);
    String tankName1=wfdTank1.name();
    tankMap wfdTank2(wfdNodeList[window]->chanAddr/0x10000,2,WFD_TANK);
    String tankName2=wfdTank2.name();
    tankMap wfdTank3(wfdNodeList[window]->chanAddr/0x10000,3,WFD_TANK);
    String tankName3=wfdTank3.name();
    tankMap wfdTank4(wfdNodeList[window]->chanAddr/0x10000,4,WFD_TANK);
    String tankName4=wfdTank4.name();
    float SIZE=.007;
    float OFF=.015;
    float YM=.02+.03*(wfdNodeListLength<4);
    float XM=.13;
    igtext_(ntx+dntx-XM,ymin+YM+4*OFF,tankName4,SIZE,0.0,"R",tankName1.length(),1);
    igtext_(ntx+dntx-XM,ymin+YM+3*OFF,tankName3,SIZE,0.0,"R",tankName2.length(),1);
    igtext_(ntx+dntx-XM,ymin+YM+2*OFF,tankName2,SIZE,0.0,"R",tankName3.length(),1);
    igtext_(ntx+dntx-XM,ymin+YM+1*OFF,tankName1,SIZE,0.0,"R",tankName4.length(),1);
    igtext_(ntx+dntx-XM,ymin+YM+0*OFF,"NOBITS" ,SIZE,0.0,"R",6,1);
    if(window==wfdNodeListLength-1)
    {
      igtext_(dntx+.03, ymax, "mV", .02, 0.0, "L", 2,1);
    }
    if(!window)
    {
      igtext_(.5*ntx+dntx, ymin-.05, "[m]sec", .02, 0.0, "C", 6,1);
    }
    for(int index=0; index<5; index++)
    {
      if (lcolor)
      {
	igset_("PLCI",bitColorMap[index],4); //line color
	igset_("PMCI",bitColorMap[index],4); //marker color
      }
      else
      {
	igset_("LTYP",bitLineMap[index],4);    // line type
      }
      if(index)
      {
	igset_("MTYP",bitMarkerMap[index-1],4); //marker type
	igset_("MSCF",size); // marker size
      }

      float XOFF=.055;
      float XWID=.033;
      float MOFF=.04;
      float XX[2]={ntx-dntx-XM-XOFF-XWID,ntx-dntx-XM-XOFF};
      float YY[2]={ymin+YM+index*OFF+.5*SIZE,ymin+YM+index*OFF+.5*SIZE};
      ipl_(2,XX,YY);
      
      if(index)
      {
	XX[0]+=MOFF;
	ipm_(1,XX,YY);
      }
    }

    iselnt_(100+window*100);

    // here are parameters to help with plotting
    int sample=0; 
    int overFlow=0; // flag so we know when to interpolate at the edge of window
    float thisTime=float(wfdNodeList[window]->time[sample]);
    int maxHits=wfdNodeList[window]->numHits;
    int sameColor=1;   //flag for if color or point style has changed
    int oldBitColor=0, newBitColor=0; // the bit that sets the line color
    float newBitPoint[4]={0,0,0,0}; // the other bits only get markers
    float oldBitPoint[4]={0,0,0,0};

    // scan forward to first point we wish to plot
    while( thisTime<tmin && sample<maxHits ) 
    {
      sample++;
      thisTime=float(wfdNodeList[window]->time[sample]);
    }

    //Choose starting color and marker types
    //Currently it starts at 0, can we find a more suitable color?
    if(sample<maxHits && wfdBitList[window]!=15)
    {
      // if the user specified the plot specifically in terms of
      // an input (ie by tank name or by erp box) then favor that input.
      if((1<<(wfdBitList[window]-1))&wfdNodeList[window]->dBit[sample])
      {
	// remember, wfdBitList is a number between 1 and 4 (not 0)
	oldBitColor=wfdBitList[window];
      }
    }
    else if(sample<maxHits)
    {
      // otherwise, choose a bit that is on to be the main color
      // this algorithm chooses the highest such bit (last surviving)
      for(int i=0; i<4; i++)
      {
	if((1<<i)&wfdNodeList[window]->dBit[sample])
	{
	  oldBitColor=i+1;
	}
      }
    }
    if(sample<maxHits)
    {
      for(int marker=0; marker<4; marker++)
      {
	oldBitPoint[marker]=0;
	if(((1<<marker)&wfdNodeList[window]->dBit[sample]) && 
	   (oldBitColor!=(marker+1)))
	{
	  oldBitPoint[marker]=1;
	}
      }
    }

    // now read data in non-zero-suppressed chunks
    while(thisTime<=tmax && sample<maxHits)
    {
      float timeChunk[9999],voltChunk[9999];
      int n=0;
      float lastTime;
      float lastVolt;
      
      float thisVolt=wfdNodeList[window]->mVolt(sample,26);
      
      if(sample)
      {
	lastTime=thisTime-5.0;
	lastVolt=wfdNodeList[window]->mVolt(sample-1,26);
      }
      else
      {
	lastTime=wfdNodeList[window]->tStart-5;
	lastVolt=0;
      }
      if(dash_dbg_lev_()==1)
      {
	cout << "Popping off a piece of waveform" << endl;
	cout << "window edges:" << tmin << " " << tmax << " "
	  << vmin << " " << vmax << endl;
	cout << "current color index:" << oldBitColor << endl;
	cout << "current polymarkers on:" ;
	if(oldBitPoint[0])cout << 1 << " ";
	if(oldBitPoint[1])cout << 2 << " ";
	if(oldBitPoint[2])cout << 3 << " ";
	if(oldBitPoint[3])cout << 4 ;
	cout << endl;
	cout << "sample\ttime\t\tmvolt\tdBit\n";
      }
      while(((thisTime - lastTime) == 5.0 ) && sample<maxHits
	    && thisVolt>=vmin && sameColor && thisTime<=tmax)
      {
	if(dash_dbg_lev_()==1)
	  cout << sample << "\t" << thisTime << "\t" 
	    << wfdNodeList[window]->mVolt(sample,26) << 
	      "\t" << wfdNodeList[window]->dBit[sample] << endl;
	if(overFlow)
	{
	  // the last point was out of range so to make things
	  // prettier lets interpolate
	  // (I have to do this because CLIP isn't working right)
	  overFlow=0;
	  if(sample)
	  {
	    if(thisTime-wfdNodeList[window]->time[sample-1]==5)
	    {
	      float prevVolt=wfdNodeList[window]->mVolt(sample-1,26);
	      float slope=(thisVolt-prevVolt)/5.0;
	      float deltat=(vmin-prevVolt)/slope;
	      if(deltat>=0.0 || deltat<=5.0)
	      {
		// interpolation successful
		timeChunk[n]=-(thisTime+deltat)/1000.;
		voltChunk[n]=vmin;
		n++;
	      }
	    }
	  }
	}
	timeChunk[n]=-thisTime/1000.;
	voltChunk[n]=thisVolt;
	n++;
	sample++;
	if(sample<maxHits && thisTime<=tmax)
	{
	  // get next point
	  // store old params
	  lastTime=thisTime;
	  thisTime=float(wfdNodeList[window]->time[sample]);
	  lastVolt=thisVolt;
	  thisVolt=wfdNodeList[window]->mVolt(sample,26);

	  // if we went under min, interpolate a point and set a flag
	  if(thisVolt<vmin && (thisTime-lastTime)==5.0)
	  {
	    overFlow=1;
	    float slope=(thisVolt-lastVolt)/5.0;
	    float deltat=(vmin-lastVolt)/slope;
	    if(deltat>=0.0 || deltat<=5.0)
	    {
	      // interpolation successful
	      timeChunk[n]=-(lastTime+deltat)/1000.;
	      voltChunk[n]=vmin;
	      n++;
	    }
	  }

	  // now lets see if the colors changed

	  newBitColor=oldBitColor;  // default to color unchanged
	  newBitPoint[0]=0; 
	  newBitPoint[1]=0;
	  newBitPoint[2]=0;
	  newBitPoint[3]=0;
	  short thisdBit=wfdNodeList[window]->dBit[sample];
	  sameColor=1;
	  if(!oldBitColor)
	  {
	    // we haven't plotted a real color yet, can we now?
	    for(int i=0; i<4; i++)
	    {
	      if((1<<i)&thisdBit)
	      {
		newBitColor=i+1;
		sameColor=0;
	      }
	    }
	  }
	  else if(!( (1<<(oldBitColor-1) & thisdBit))) 
	  {
	    // the old color is no longer valid, get a new one
	    for(int i=0; i<4; i++)
	    {
	      if((1<<i)&thisdBit)
	      {
		newBitColor=i+1;
		sameColor=0;
	      }
	    }
	  }
	  if(!thisdBit && oldBitColor)
	  {
	    // no bits are on so use the zero color (pre/post samples)
	    newBitColor=0;
	    sameColor=0;
	  }
	  // also, pick the new point types out from scratch
	  for(int i=0; i<4; i++)
	  {
	    if( ( (1<<i) & thisdBit ) && newBitColor!=(i+1))
	    {
	      newBitPoint[i]=1;
	      if(!oldBitPoint[i])sameColor=0;
	    }
	    else
	    {
	      newBitPoint[i]=0;
	      if(oldBitPoint[i])sameColor=0;
	    }
	  }	  
	  // if the color changed add the point to the list
	  // (if we haven't already! The overflow check didn't care about
	  // color)
	  if(!sameColor)
	  {
	    timeChunk[n]=-thisTime/1000.;
	    voltChunk[n]=thisVolt;
	    n++;
	  }
	}
      }

      if(wfdNodeList[window]->mVolt(sample,26)<vmin)sample++;
      
      if(n>=2)
      {
	if (lcolor)
	{
	  igset_("PLCI",bitColorMap[oldBitColor],4); //line color
	  igset_("PMCI",bitColorMap[oldBitColor],4); //marker color
	}
	else
	{
	  igset_("LTYP",bitLineMap[oldBitColor],4);    // line type
	}
	ipl_(n,timeChunk,voltChunk);
	for(int i =0; i< 4; i++)
	{
	  if(oldBitPoint[i])
	  {
	    igset_("MTYP",bitMarkerMap[i],4); //marker type
	    ipm_(n,timeChunk,voltChunk);
	  }
	}
      }
      
      // new colors become old colors
      sameColor=1;
      oldBitColor=newBitColor;
      for(int i=0; i<4; i++)oldBitPoint[i]=newBitPoint[i];
	
    }
  }
  iuwk_(0,1);
}
