//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <stdio.h>
#include <math.h>
#include "Protocol.h"
#include "Data.h"
#include "Sim.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TProtocolForm *ProtocolForm;
//---------------------------------------------------------------------------
__fastcall TProtocolForm::TProtocolForm(TComponent* Owner)
  : TForm(Owner)
{
  

}
//---------------------------------------------------------------------------


void __fastcall TProtocolForm::Parse_Protocol()
{
  AnsiString buffer, sval, token[20];
  int    iflash, Flashes, last_token, Irradiances;
  int    iData = 1;
  double  FlashLen, DelLen, DelInc, Delay, SecLen;
  double  flashtt, irrtt, timeon;
  double  IrrPower, IrrInc, IrrLen;

  DataForm->FLASH->Clear();
  DataForm->IRR->Clear();
  DataForm->IrrChart->Update();
  DataForm->IrrChart->UndoZoom();
  DataForm->FlashChart->Update();
  int nolines = DataForm->Protocol->Lines->Count;
  NoFlashes = 0;
  flashno   = 1;
  flashtt   = 0;
  irrtt     = 0;
  timeon    = 0;
  Flashes   = 10;       //---- Defaults
  FlashLen  = 1;
  Delay     = 5;
  DelInc    = 1;

  irrno     = 0;
  IrrPower  = 10;
  IrrInc    = 0;
  IrrLen    = 1;
  flashtime[0] = 0;
  flashlen[0]  = 0;
  DataForm->tim[0] = 0;
  DataForm->ex[0]  = 0;
  SimForm->tim[0]  = 0;
  SimForm->ex[0]   = 0;
  int icycle = 0;
  for (int iline = 0; iline < nolines; iline++)
  {
    if(iline == 0)
      DataForm->CyclePumpStart[0] = flashno;
    if(iline == 1)
      DataForm->CycleDecStart[0] = flashno;
    for(int it = 0; it < 20; it ++) token[it] = "";
    if (nolines == 0) break;
    buffer = DataForm->Protocol->Lines->Strings[iline];
    int ichar, itoken, notokens;
    ichar = 1; itoken = 0;
    sval = "";
    if(buffer.Length() > 3) do                                //get tokens from the Lines
    {
      while (!(buffer[ichar] == ' ') && !(buffer[ichar] == ';') && !(buffer[ichar] == ','))
      {
        sval += buffer[ichar];
        ichar++;
      }
      token[itoken] = sval;
      sval = "";
      itoken ++;
      while ((buffer[ichar] == ' ') || (buffer[ichar] == ',')) ichar ++;
    }
    while (!(buffer[ichar] == ';'));
    last_token = itoken - 1;
    itoken = 0;
    if(token[0] == "flash")                     //------- FLASH Command ------
    {
      //flashtt = timeon;
      Flashes = StrToInt(token[1]);
      for(int ifield = 1; ifield < (last_token + 1)/2; ifield ++)
      {
        float tokenval = StrToFloat(token[2 * ifield + 1]);
        if(token[2 * ifield] == "len")   FlashLen     = tokenval;
        if(token[2 * ifield] == "del")   Delay        = tokenval;
        if(token[2 * ifield] == "start") flashtt      = tokenval;
        if(token[2 * ifield] == "inc")   DelInc       = tokenval;
      }
      for(int i = 0; i < Flashes; i++)
      {
        flashlen[flashno] = FlashLen;
        flashtime[flashno] = flashtt;
        if(token[last_token] == "p")
        {
          DataForm->FLASH->AddXY(flashtt, 0, "", clTeeColor);
          DataForm->FLASH->AddXY(flashtt, DataForm->ExPower, "", clTeeColor);
          DataForm->FLASH->AddXY((flashtt + FlashLen), DataForm->ExPower, "", clTeeColor);
          DataForm->FLASH->AddXY((flashtt + FlashLen), 0, "", clTeeColor);
          DataForm->FLASH->AddXY((flashtt + Delay - 0.01), 0, "", clTeeColor);
        }
        DataForm->tim[iData] = flashtt;
        DataForm->ex[iData] = DataForm->ExPower * FlashLen;  // in microJoules
        DataForm->excal[iData] = DataForm->ex[iData] * 3.3e-8;
        DataForm->exlen[i]  = FlashLen;
        SimForm->tim[iData] = flashtt + FlashLen;     //--- to record f at the end of the flash
        flashtt += Delay;
        Delay *= DelInc;
        flashno ++;
        iData ++;

      }
      if(iline == 0)
        DataForm->CyclePumpEnd[0] = flashno - 1;
      if(iline == 1)
        DataForm->CycleDecEnd[0] = flashno - 1;
      timeon = flashtt;
    }
    if(token[0] == "irrad")                           //--- IRRADIANCE Command
    {
      if(irrno > 0) irrno --;
      //irrtt = timeon;
      Irradiances = StrToInt(token[1]);
      for(int ifield = 1; ifield < (last_token + 1)/2; ifield ++)
      {
        float tokenval = StrToFloat(token[2 * ifield + 1]);
        if(token[2 * ifield] == "pwr")      IrrPower     = tokenval;
        if(token[2 * ifield] == "pwrinc")   IrrInc       = tokenval;
        if(token[2 * ifield] == "len")      IrrLen       = tokenval * 1000;
        if(token[2 * ifield] == "start")    irrtt        = tokenval * 1000;
      }
      for(int i = 0; i < Irradiances; i++)
      {
        irrpower[irrno] = IrrPower;
        irrlen[irrno]   = IrrLen;
        irrtime[irrno]   = irrtt;
        if(token[last_token] == "p")
        {
          if(i == 0)
          {
            //DataForm->IRR->AddXY(-0.001, 0, "", clTeeColor);
            DataForm->IRR->AddXY((irrtt - 0.0001) * 0.001, 0, "", clTeeColor);
          }
          DataForm->IRR->AddXY(irrtt * 0.001, IrrPower, "", clTeeColor);
          DataForm->IRR->AddXY((irrtt + IrrLen-0.01) * 0.001, IrrPower, "", clTeeColor);
        }
        irrtt    += IrrLen;
        IrrPower += IrrInc;
        if(IrrPower < 0) IrrPower = 0;
        irrno ++;
      }
      timeon = irrtt;
      IrrPower = 0;
      if(token[last_token] == "p")
      DataForm->IRR->AddXY((irrtt) * 0.001, 0, "", clTeeColor);
    }
    if(token[0] == "delay")              //-------  DELAY Command ------
    {
      //timeon += StrToFloat(token[1]) * 1000;
      float del = StrToFloat(token[1]) * 1000;
      irrpower[irrno] = 0;
      irrlen[irrno]   = del;
      irrtime[irrno]   = irrtt;
      irrtt += del;
      irrno ++;
    }
    irrpower[irrno] = 0;
    irrtime[irrno]  = irrtt;
    irrno ++;
  }
//----- load flash info -------------------
  flashno -= 1;
  irrno   -= 1;
  float irrmax = DataForm->IRR->MaxYValue();
  DataForm->IrrChart->LeftAxis->SetMinMax(-irrmax*0.05, irrmax * 1.05);
  DataForm->FlashChart->LeftAxis->SetMinMax(-DataForm->ExPower*0.05, DataForm->ExPower * 1.05);
  DataForm->nodata = flashno;
  for(int id = 1; id < flashno + 1; id ++)
  {
    DataForm->tim[id] = SimForm->tim[id];
    DataForm->exlen[id] = flashlen[id];
    //   --- Power proportional to flash lenght, until we read the EX signal ---
    DataForm->ex[id]  = DataForm->ExPower * flashlen[id];
  }
  float deltat = DataForm->tim[2] - DataForm->tim[1];
  if(!(DataForm->tim[1] == deltat))
  {
      deltat = DataForm->tim[1] - deltat;
      for(int id = 1; id < flashno + 1; id++)
      DataForm->tim[id] -= deltat;
  }
  DataForm->dt[0] = 0;
  for(int id = 1; id < flashno + 1; id++) DataForm->dt[id] = DataForm->tim[id]-DataForm->tim[id-1];

  DataForm->FitStart = 1;
  DataForm->FitEnd   = flashno;
  char    text[80];

//----- Load sheduler  ----------------------
  int iff = 1;
  int irr = 0;
  int iev = 0;
  float fftime = flashtime[iff];
  float rrtime = irrtime[irr];
  float irradpower = 0;
  bool Onflash = false;
  bool Onirr   = false;

  seq[0] = 0x03;
  seq[1] = 0x00;
  //seq[2] = 0x03;
  seq[2] = 0x0d;
  seq[3] = 0x00;  //80 us dark signal measurement prior to flashes
  iseq = 4;
  boolean prescalerON;
  unsigned int seqword = 0;
  do
  {
    seqword = 0;
    if((fftime <= rrtime) && (iff <= flashno))      //at flash start
    {
      SimForm->evtime[iev] = fftime;
      if(fabs(fftime - rrtime) > 0.01)
        SimForm->evvalu[iev] = DataForm->ExPower;
      SimForm->evvalu[iev] += irradpower;
      fftime += flashlen[iff];
      Onflash = true;
      iev ++;
//--- SEQUENCER ----
      //seqflashlen = int(flashlen[iff]/0.0833333 + 0.01);      //FRR
      seqflashlen = int(flashlen[iff]/0.8 + 0.01);        //B2C Lift
      //if(iff == 1) seqflashlen += 3;
      //if(flashtime[iff] - flashtime[iff - 1] > 40) seqflashlen += 3;




      //if(iff < flashno) delaylen = (flashtime[iff + 1] - flashtime[iff])/0.0833333;
      if(iff < flashno) delaylen = (flashtime[iff + 1] - flashtime[iff])/0.8;

      //if(iff == flashno) delaylen = seqflashlen + 20;
      seqprescaler = 0;
      if(!(delaylen > 1048575.0)) prescalerON = false;
      if(delaylen > 1048575.0)
      {
        seqprescaler = 1;
        delaylen /= 64.0;
        DataForm->SeqTime *= 64;
        if(prescalerON) seqflashlen --;      //correct for the flashlen stretch
        prescalerON = true;                  //when presclaer is ON
      }
      if(delaylen > 1048575.0)
      {
        seqprescaler = 2;
        delaylen /= 64.0;
      }
      if(delaylen > 1048575.0)
      {
        seqprescaler = 3;
        delaylen /= 64.0;
      }
      seqdelaylen = int(delaylen + 0.01);
      seqword = 3;         //Flash & Delay, FIFO ON  during delay

      seqword += seqprescaler * 4 + seqflashlen * 16 + seqdelaylen * 4096;
      seq[iseq] = seqword & 0x000000ff;
      seqword /= 256;
      seq[iseq + 1] = seqword & 0x000000ff;
      seqword /= 256;
      seq[iseq + 2] = seqword & 0x000000ff;
      seqword /= 256;
      seq[iseq + 3] = seqword & 0x000000ff;
      seqword /= 256;

//---- TEST ONLY for debugging the hardware
//      seq[iseq] = iseq * 4;
//      seq[iseq + 1] = iseq * 4 + 1;
//      seq[iseq + 2] = iseq * 4 + 2;
//      seq[iseq + 3] = iseq * 4 + 3;
//      seq[iseq] = iff;
//      seq[iseq + 1] = iff;
//      seq[iseq + 2] = iff;
//      seq[iseq + 3] = iff;
//      if(iseq > 60) iseq = 60;
//-----------------------------------------
      iseq += 4;
    }
    else if(irr <= irrno)
    {
      SimForm->evtime[iev] = rrtime;
      SimForm->evvalu[iev] = irrpower[irr];
      irradpower = irrpower[irr];
      if(Onflash) SimForm->evvalu[iev] += DataForm->ExPower;
      iev ++;
      irr ++;
      if(irr <= irrno) rrtime = irrtime[irr];
      else rrtime = 1.e20;
    }
    if((fftime <= rrtime) && (iff <= flashno) && Onflash) //at flash end
    {
      SimForm->evtime[iev] = fftime;
      SimForm->evvalu[iev] = irradpower;
      Onflash = false;
      iev ++;
      iff ++;
      fftime = flashtime[iff];
      Onflash = false;
    }
  }while((irr <= irrno) || (iff <= flashno));
  seq[iseq] = 0x03;
  seq[iseq + 1] = 0x00;
  seq[iseq + 2] = 0x04;
  seq[iseq + 3] = 0x00;  //10 us dark after the last flash
  iseq += 4;


//--- SEQUENCER PAUSE CODE ---
  seq[iseq]     = 0xf0;
  seq[iseq+1]   = 0x00;
  seq[iseq + 2] = 0x00;
  seq[iseq + 3] = 0x00;

  seq[iseq + 4] = 0xf0;
  seq[iseq + 5] = 0x00;
  seq[iseq + 6] = 0x00;
  seq[iseq + 7] = 0x00;
  sequencer_len = iseq + 4;
//----------------------------
  DataForm->EV->Clear();
  DataForm->EV->AddXY(0, 0, "", clTeeColor);
  /*
  for(int ip = 0; ip < iev; ip ++)
  {
    DataForm->EV->AddXY(SimForm->evtime[ip] * 0.001, SimForm->evvalu[ip], "", clTeeColor);
    if(ip < iev - 1)
    DataForm->EV->AddXY(SimForm->evtime[ip + 1] * 0.001, SimForm->evvalu[ip], "", clTeeColor);
  }
  */
  SimForm->noev = iev - 1;
  DataForm->ExLenParsed = true;
}

void __fastcall TProtocolForm::Get_Protocol()
{
   DataForm->OpenFileDialog->FileName = NULL;
  DataForm->OpenFileDialog->InitialDir = DataForm->CurrentDir;
  DataForm->OpenFileDialog->InitialDir += "\\Protocols";
  DataForm->OpenFileDialog->Filter = "Protocol files (*.ptc)|*.PTC";
  if(DataForm->OpenFileDialog->Execute())
  {
    DataForm->Protocol->Lines->LoadFromFile(DataForm->OpenFileDialog->FileName);
  }
}

void __fastcall TProtocolForm::Store_Protocol()
{
  AnsiString FileName;
   DataForm->OpenFileDialog->FileName = NULL;
  DataForm->SaveFileDlg->InitialDir = DataForm->CurrentDir;
  DataForm->SaveFileDlg->InitialDir += "\\Protocols";
  DataForm->SaveFileDlg->Filter = "Protocol files (*.ptc)|*.PTC";
  if(DataForm->SaveFileDlg->Execute())
  {
    FileName = DataForm->SaveFileDlg->FileName;
    if(FileName.Pos(".ptc") == 0) FileName += ".ptc";
    DataForm->Protocol->Lines->SaveToFile(FileName);
  }
}
