#ifndef FACT_EventBuilder
#define FACT_EventBuilder

#include "FAD.h"

/* global variables; 
   to avoid race canoditions, only one thread is allowed to write 
   the name of the variable defines which process shall write it:

   g_XXX : main control thread
   gi_XX : input thread (reading from camera)
   gw_XX : write thread (writing to disk)
   qp_XX : processing thread(s) (processing data, eg. soft-trig)

*/
extern int  g_reset     ;  //>0 = reset different levels of eventbuilder
extern size_t g_maxMem  ;  //maximum memory allowed for buffer

extern FACT_SOCK g_port[NBOARDS] ;  // .port = baseport, .addr=string of IP-addr in dotted-decimal "ddd.ddd.ddd.ddd"

extern uint gi_NumConnect[NBOARDS];   //4 crates * 10 boards

class DrsCalibration;

enum FileStatus_t
{
    kFileNotYetOpen,
    kFileOpen,
    kFileClosed
};

enum CloseRequest_t
{
    kRequestNone = 0,
    kRequestManual = 1,
    kRequestTimeout = 2,
    kRequestConnectionChange = 4,
    kRequestEventCheckFailed = 8
};


struct RUN_CTRL2
{
    int64_t runId ;      // Run number

    time_t openTime;     // Time when first event (first board) was received
    time_t lastTime;     // Time when last event was received (set when first board data received)
    time_t closeTime;    // Time when run should be closed
    uint32_t night;      // night as int as determined for this run

    uint32_t lastEvt;    // number of events received (counted when the first board was received)
    uint32_t maxEvt;     // maximum number which should be written to file

    uint16_t roi0;       // roi for normal pixels
    uint16_t roi8;       // roi for pixels8

    std::string runType;

    FileStatus_t fileStat;
    int closeRequest;

    std::shared_ptr<DrsCalibration> calib;

    RUN_CTRL2() : runId(-1), lastTime(0), lastEvt(0), maxEvt(1<<31), fileStat(kFileNotYetOpen), closeRequest(kRequestNone)
    {
        // runId   = -1;
        // fileId  = kFileNotYetOpen;
        // lastEvt =  0;    // Number of events partially started to read
        // actEvt  =  0;    // Number of written events
        // maxEvt  = 1<<31; // max number events allowed (~2400min @ 250Hz)

    }
    //~RUN_CTRL2();
};

struct EVT_CTRL2
{
    int64_t   runNum;
    uint32_t  evNum;

    uint32_t  trgNum;
    uint32_t  trgTyp;
    uint32_t  fadLen;

    uint32_t  nBoard;
    int16_t   board[NBOARDS];

    uint16_t  nRoi;
    uint16_t  nRoiTM;

    timeval   time;
    uint8_t   Errors[4];

    std::shared_ptr<PEVNT_HEADER> FADhead;
    EVENT *fEvent;

    std::shared_ptr<RUN_CTRL2> runCtrl;

    EVT_CTRL2(std::shared_ptr<RUN_CTRL2> run=std::shared_ptr<RUN_CTRL2>()) : runNum(-1), runCtrl(run)
    {
        Errors[0] = 0;
        Errors[1] = 0;
        Errors[2] = 0;
        Errors[3] = 0;

        //flag all boards as unused
        nBoard = 0;
        for (int b=0; b<NBOARDS; b++)
            board[b] = -1;
    }

    operator RUN_HEAD() const
    {
        RUN_HEAD rh;

        rh.Nroi    = nRoi;
        rh.NroiTM  = nRoiTM;
        rh.RunTime = time.tv_sec;
        rh.RunUsec = time.tv_usec;

        memcpy(rh.FADhead, FADhead.get(), NBOARDS*sizeof(PEVNT_HEADER));

        return rh;
    }

    void initEvent(const std::shared_ptr<PEVNT_HEADER> &mem)
    {
        FADhead = mem;
        fEvent  = reinterpret_cast<EVENT*>(mem.get()+NBOARDS);

        memset(fEvent->Adc_Data, 0, (NPIX+NTMARK)*2*nRoi);

        //flag all pixels as unused
        for (int k = 0; k < NPIX; k++)
            fEvent->StartPix[k] = -1;

        //flag all TMark as unused
        for (int k = 0; k < NTMARK; k++)
            fEvent->StartTM[k] = -1;

        fEvent->NumBoards   = 0;
        fEvent->SoftTrig    = 0;
        fEvent->PCTime      = time.tv_sec;
        fEvent->PCUsec      = time.tv_usec;
        fEvent->Roi         = nRoi;
        fEvent->RoiTM       = nRoiTM;
        fEvent->EventNum    = evNum;
        fEvent->TriggerNum  = trgNum;
        fEvent->TriggerType = trgTyp;
    }
};

#endif
