/********************************************************************\

  RawDataCTX.cc

  Class for raw data handling of the DRS 2-based DAQ

  Oliver Grimm
  
\********************************************************************/

#include "RawDataCTX.h"

// *** Constructor
RawDataCTX::RawDataCTX(bool BeSilent) {
  RHeader = new RunHeader; 
  EHeader = new EventHeader;
  FileOpen = false;
  Silent = BeSilent;
}

// *** Destructor
RawDataCTX::~RawDataCTX() {
  if(FileOpen) CloseDataFile();

  delete RHeader;
  delete EHeader;
}

// *** Open raw data file
CTX_ErrCode RawDataCTX::OpenDataFile(char *Filename, FILE *fptr) {
    
  if(FileOpen) CloseDataFile();
  // Open file
  if ((Rawfile = fopen(Filename, "r")) == NULL) {
    if(!Silent) printf("Error: Could not open file: %s\n", Filename);
    return CTX_FOPEN;
  }
  // Read run header
  if (fread(RHeader, sizeof(RunHeader), 1, Rawfile) != 1) {
    if(!Silent) printf("Error: Could not read run header\n");
    fclose(Rawfile);
    return CTX_RHEADER;  
  }
  // Read board structures
  BStruct = new BoardStructure [RHeader->NCMCBoards];
  if(fread(BStruct, sizeof(BoardStructure), RHeader->NCMCBoards, Rawfile) != RHeader->NCMCBoards) {
    if(!Silent) printf("Error: Could not read (all) board structures\n");
    fclose(Rawfile);
    delete[] BStruct;
    return CTX_BSTRUCT;
  }
  // Allocate memory for event data
  Data = new short[RHeader->NCMCBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples];
  FileOpen = true;
  
  // If requested, print run header (including board structures) to file 
  if(fptr != NULL) {
    int RAhour, RAmin, RAsec, DEChour, DECmin, DECsec;

    fprintf(fptr, "Magic number      %x\n", RHeader->MagicNum);
    fprintf(fptr, "Data format:      %d\n", RHeader->DataFormat);
    fprintf(fptr, "DAQ compilation:  %s\n", RHeader->DAQVersion);         
    fprintf(fptr, "Source:           %s\n", RHeader->Source);
    fprintf(fptr, "Run type:         %c\n", RHeader->Type);
    fprintf(fptr, "Run number:       %u\n", RHeader->RunNumber);
    fprintf(fptr, "Events:           %u\n", RHeader->Events);
    fprintf(fptr, "CMC Boards:       %u\n", RHeader->NCMCBoards);
    fprintf(fptr, "DRS chips:        %u\n", RHeader->NChips);
    fprintf(fptr, "Channels/chip:    %u\n", RHeader->NChannels);
    fprintf(fptr, "Samples:          %u\n", RHeader->Samples);
    fprintf(fptr, "Offset:           %d\n", RHeader->Offset);

    RAsec   = (int) (RHeader->SourceRA)%60;
    RAmin   = (int) (RHeader->SourceRA/60)%60;
    RAhour  = (int) (RHeader->SourceRA/3600);
    DECsec  = (int) (RHeader->SourceDEC)%60;
    DECmin  = (int) (RHeader->SourceDEC/60)%60;
    DEChour = (int) (RHeader->SourceDEC/3600);

    fprintf(fptr, "Source RA:        %f (%d %d %d)\n", RHeader->SourceRA, RAhour, RAmin, RAsec);
    fprintf(fptr, "Source DEC:       %f (%d %d %d)\n", RHeader->SourceDEC, DEChour, DECmin, DECsec);

    RAsec   = (int) (RHeader->TelescopeRA)%60;
    RAmin   = (int) (RHeader->TelescopeRA/60)%60;
    RAhour  = (int) (RHeader->TelescopeRA/3600);
    DECsec  = (int) (RHeader->TelescopeDEC)%60;
    DECmin  = (int) (RHeader->TelescopeDEC/60)%60;
    DEChour = (int) (RHeader->TelescopeDEC/3600);

    fprintf(fptr, "Telescope RA:     %f (%d %d %d)\n", RHeader->TelescopeRA, RAhour, RAmin, RAsec);
    fprintf(fptr, "Telescope DEC:    %f (%d %d %d)\n", RHeader->TelescopeDEC, DEChour, DECmin, DECsec);

    fprintf(fptr, "Start year:       %u\n", RHeader->StartYear);
    fprintf(fptr, "Start month:      %u\n", RHeader->StartMonth);
    fprintf(fptr, "Start day:        %u\n", RHeader->StartDay);
    fprintf(fptr, "Start hour:       %u\n", RHeader->StartHour);
    fprintf(fptr, "Start minute:     %u\n", RHeader->StartMinute);
    fprintf(fptr, "Start second:     %u\n", RHeader->StartSecond);
    fprintf(fptr, "End year:         %u\n", RHeader->EndYear);
    fprintf(fptr, "End month:        %u\n", RHeader->EndMonth);
    fprintf(fptr, "End day:          %u\n", RHeader->EndDay);
    fprintf(fptr, "End hour:         %u\n", RHeader->EndHour);
    fprintf(fptr, "End minute:       %u\n", RHeader->EndMinute);
    fprintf(fptr, "End second:       %u\n", RHeader->EndSecond);

    for (unsigned int i=0; i<RHeader->NCMCBoards; i++) {
      fprintf(fptr, "*** Board %d ***\n", i);
      fprintf(fptr, "Serial number:            %d\n", BStruct[i].SerialNo);
      fprintf(fptr, "Sampling frequency [GHz]: %.3f\n", BStruct[i].NomFreq);
      fprintf(fptr, "Temperature [C]:          %.3f\n", BStruct[i].BoardTemp);  
      fprintf(fptr, "Scale factor:             %.3f\n", BStruct[i].ScaleFactor);
    }     
  }
  return CTX_OK;
}

// *** Close raw data file
CTX_ErrCode RawDataCTX::CloseDataFile() {

  if(!FileOpen) return CTX_NOTOPEN;

  if (fclose(Rawfile) == EOF) {
    if(!Silent) perror("Could not close file");
    return CTX_FCLOSE;
  }
  
  delete[] BStruct;
  delete[] Data;
  
  FileOpen = false;
  return CTX_OK;
}

// *** Read next event from file
CTX_ErrCode RawDataCTX::ReadEvent(int EventNo, FILE *fptr) {
    
  if(!FileOpen) {
    if(!Silent) printf("Error: No data file open.\n");
    return CTX_NOTOPEN;
  }
  
  // Move file pointer to desired event header (if zero read next event)
  if(EventNo!=0 && fseek(Rawfile, sizeof(RunHeader)+sizeof(BoardStructure)*RHeader->NCMCBoards+(EventNo-1)*(sizeof(EventHeader)+RHeader->NCMCBoards*RHeader->NChips*
      RHeader->NChannels*RHeader->Samples*sizeof(short)), SEEK_SET)!=0) {
    if(!Silent) printf("Error: Could not move to requested event\n");
    return CTX_SEEK;
  }

  // Read event header
  if (fread(EHeader, sizeof(EventHeader), 1, Rawfile) != 1) {
    if(feof(Rawfile)==0) {
      if(!Silent) printf("Error: Could not read event header\n");
      return CTX_EHEADER;
    }
    else return CTX_EOF;  
  }
  if(fread(Data, sizeof(short), RHeader->NCMCBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples, Rawfile)
	  != RHeader->NCMCBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples) {
    if(!Silent) printf("Error: Could not read (all) data\n");
    return CTX_DATA;    
  }

  // If requested, print event header to file 
  if(fptr != NULL) {
    fprintf(fptr, "Name:            %s\n",    EHeader->Name);
    fprintf(fptr, "Event number:    %u\n",    EHeader->EventNumber);
    fprintf(fptr, "Time [s]:        %f\n",    EHeader->TimeSec);
    fprintf(fptr, "Trigger type:    0X%0X\n", EHeader->TriggerType);
  }
  
  return CTX_OK;
}

// *** Check if file currently open
bool RawDataCTX::IsFileOpen() {
  return FileOpen;
}

