#ifndef SHARED_MEM_BUFFER_INCLUDED_H
#define SHARED_MEM_BUFFER_INCLUDED_H

#include <cinttypes>
#include <atomic>

#include <QSharedMemory>
#include <QtGlobal>


bool shdMem_firstUse(void);

// Vorsicht: im shared memory ist kein QString erlaubt!!!!!!!!!!!!!!!!!!!!!!
//    nur standard C Typen!!!!!!
//    also auch kein QByteArray o.รค.

// Vorsicht: Zugriffe auf Comport NICHT ins shared mem --> Absturz!!!!

struct SharedMem
{
    // ------------------ Comport Control --------------------------------
    bool     rs_portIsOpen;
    bool     AutoEmissionOn;
    bool     Sdata_serialTestResult;
    uint8_t  Sdata_pProtResultOk;
    uint16_t Sdata_receivedDataLength;
    uint8_t  Sdata_receivedDataBlock[64];
    uint8_t  ndbs, pari, nsb, br;

    uint8_t  Sdata_lastResult;
    uint8_t  Sdata_OverallResult;
    bool     Sdata_startSV;

    // ------------------ Data INPUT --------------------------------

    bool indat_savePrnPwr;
    bool indat_saveMifPwr;
    bool indat_MdbIsOn;
    //QString indat_HWversion;
    //QString indat_SWversion;
    //QString indat_DCstate;

    #define versionBufferLen   32
    char indat_HWversion[versionBufferLen];
    char indat_SWversion[versionBufferLen];
    char indat_DCstate[versionBufferLen];

    struct Sdata
    {
        uint64_t slaveUID;
        uint8_t UIDstr[8];
    } Sdata;

    struct T_globTime
    {
        // Reihenfolge nicht vertauschen!!!!!
        uint8_t     hour;
        uint8_t     minute;
        uint8_t     second;
        uint8_t     Year;
        uint8_t     Month;
        uint8_t     DayOfMonth;
        uint8_t     DayOfWeek;          // 1=monday...7
        uint8_t     reserve1;

        uint16_t     MinutesOfToday;
        uint16_t     reserve2;

        uint32_t     SecondsOfToday;

        uint8_t      IsLeapyear;
        uint8_t      nextLeap;
        uint8_t      lastLeap;
        uint8_t      hoursOfWeek;

        uint16_t     minOfWeek;
        uint16_t     hoursOfMonth;
        uint16_t     minOfMonth;
        uint16_t     dayOfYear;
        uint16_t     hoursOfYear;
        uint16_t     reserve3;

        uint32_t     minOfYear;

        uint8_t      squareOutMode;
        uint8_t      free1;
        uint16_t     reserve4;
        uint32_t     minOfMillenium;
        // bis hierher 44byts
        uint32_t    free2;
        uint32_t    free3;
        uint32_t    free4;

    } getGlobalTime;

    #define MAXNROF_AI              4
    uint16_t   AI_val[MAXNROF_AI];

    #define MAXNROF_MEASURE         4
    uint32_t   Sdata_measurement[MAXNROF_MEASURE];

    uint8_t di_doorSwitch;
    uint8_t di_vaultSwitch;
    uint8_t di_lockSwitch;
    uint8_t di_opto;
    uint8_t di_aux;
    bool di_wakeFromPtu;
    bool di_wakeFromMdb;
    bool di_PrnReady;
    bool di_CoinAttach;
    bool di_CoinEscrowOpen;
    bool di_mifCardTap;
    bool di_wakeFromModem;
    bool di_contactPwrOn;
    bool di_mifarePwrOn;
    bool di_rdbk_mdbTxd;
    bool di_AuxPwrOn;
    bool di_gsmPwrOn;
    bool di_creditPwrOn;
    bool di_printerPwrOn;
    bool di_mdbPwrOn;
    bool di_rejMot_home;
    uint8_t di_npe_sensor;

    uint8_t do_mbdRxTst;
    uint8_t do_motorBits;
    uint8_t do_serialSwitch;
    uint8_t do_ledsAndFan;
    uint8_t do_laermUndRelay;
    uint8_t do_ptuWake;
    uint8_t do_auxPower;
    uint8_t do_coinShutter;
    uint8_t do_coinEscrow;
    uint8_t do_printerPower;

    //#define NROFMIFSTATEBYTES   40
    //uint8_t Sdata_MIF_STATE[NROFMIFSTATEBYTES];
    uint8_t Sdata_MIF_DATA[64];
    //uint8_t mif_cardType;
    //uint8_t mif_cardHolder[8];
    uint8_t Sdata_MIF_ATB[64];

    #define pi_prnStateArraySize    20
    uint8_t Sdata_PRN_STATE[pi_prnStateArraySize];

    #define pi_prnFontArraySize     20
    uint8_t Sdata_PRN_FONTS[pi_prnFontArraySize];

    bool Sdata_mdb_busRdy;
    bool Sdata_mdb_V12on;
    bool Sdata_mdb_V5on;

    uint8_t Sdata_mdbNrOfRecData;
    uint8_t Sdata_RecBuff[40];

    uint8_t Sdata_empNrOfsettings;
    uint8_t Sdata_emp_settingsBuff[66];

    struct T_coin
    {
        uint8_t valid;
        uint8_t signal;
        uint8_t error;
        uint8_t pad;
        uint16_t value;
    };

    #define     MEMDEPTH_GOTCOINS       16
    struct T_coin gotCoin[MEMDEPTH_GOTCOINS];
    uint8_t ctr_gotCoin;

    uint8_t Sdata_NrOfDeviceSetting;
    uint8_t Sdata_DeviceSettingBuff[66];

    uint8_t SizeMachineIDBuff;
    uint8_t MachineIDBuff[66];

    uint32_t store_insertedAmount;
    uint16_t store_lastCoinType[64];
    uint16_t store_lastCoinValue[64];
    uint8_t  p_lastCoin;
    char     store_curPayNewCoin;

    uint64_t stor_wakSrc;
    uint8_t  stor_reason;

    uint8_t store_rbDevParamLen;
    uint8_t store_rbDevParams[66];

    uint8_t store_deviceCondLen;
    uint8_t store_deviceCond[66];

    uint8_t store_machCondLen;
    uint8_t store_machCond[66];

    uint8_t  store_DcBackupNrOfAccNr;
    uint16_t store_DcBackupAccNr[16];    // z.Z. nur 8

    #define PI_SIZOFVAULTRECORD    400
    uint8_t store_gotNrBlocksOfVaultRec;
    uint8_t store_vaultrecord[PI_SIZOFVAULTRECORD];

    uint32_t store_amount;
    uint16_t store_nrOfCoins;

    bool store_DcDataAreValid;

    uint8_t storeDCdynPrinterData[64];
    uint8_t DCdynPrinterDataActual;

    uint16_t store_DCNextAccountNumber;

    uint16_t storeMifCardTypDataLen;
    uint8_t  storeMcardTypData[64];

    // new from 6.9.23:
    #define RAW_BL_DATALEN      150
    uint8_t Sdata_rawData[RAW_BL_DATALEN];
    uint8_t Sdata_LengthRawData;

#define  numberOfJsons     36
#define  versionStringLength    16
    char    store_jsonVersion[versionStringLength][numberOfJsons];

    uint8_t Sdata_changeResult;
    uint32_t Sdata_changedAmount;
    uint8_t  store_tubeLev[64];

    uint8_t  store_bnaParameter[64];
    uint8_t  store_bnaCollect[8];
    uint8_t  store_bnaContent[64];

    // new, 8.5.24
    uint8_t store_machCon2len;
    uint8_t store_machCon2[66];




    // Mitteilung von Hwapi zu Datif:
    bool    Sdata_coinPaymentNow;
    bool    Sdata_bootloadingNow;


    // ------------------ Data OUTPUT --------------------------------

    // sendWRcmd.cpp
    #define CMDSTACKDEPTH   32
    uint16_t nextAsynchsendCmd0[CMDSTACKDEPTH];
    uint8_t  nrOfCmdsInQueue;

    #define CMD4STACKDEPTH   8
    uint16_t    nextAsynchsendCmd4[CMD4STACKDEPTH];
    uint8_t     nextCmd4para1[CMD4STACKDEPTH];
    uint8_t     nextCmd4para2[CMD4STACKDEPTH];
    uint8_t     nextCmd4para3[CMD4STACKDEPTH];
    uint8_t     nextCmd4para4[CMD4STACKDEPTH];
    uint8_t     nrOfCmds4InQueue;

    #define CMD8STACKDEPTH   4
    uint16_t  nextAsynchsendCmd8[CMD8STACKDEPTH];
    uint8_t   nextCmd8para1[CMD8STACKDEPTH];
    uint8_t   nextCmd8para2[CMD8STACKDEPTH];
    uint16_t  nextCmd8para3[CMD8STACKDEPTH];
    uint32_t  nextCmd8para4[CMD8STACKDEPTH];
    uint8_t   nrOfCmds8InQueue;

    #define SENDASYDAT_BUFFSIZE     200
    uint8_t sendAsynchDataBuf[SENDASYDAT_BUFFSIZE]; // no stack, only ONE buffer
    uint8_t sendAsyDatLen;

    #define MDBSEND_BUFFSIZE    64
    uint8_t     Sdata_mdbSendBuffer[MDBSEND_BUFFSIZE];
    uint8_t     Sdata_mdbSendLen;

    uint8_t     prnDataParameters[4];
    uint8_t     prnDataBufferUser;


    // ONE printer doc consists of 20 x 64 byte
    #define MAXNROF_PRNBYTES   64
    #define MAXNROF_PRNBLOCKS  20
    char        Sdata_PRN_TEXT[MAXNROF_PRNBLOCKS][MAXNROF_PRNBYTES];
    uint8_t     pPrnDataBuff;        // points to next PRINTER_BLOCK


    //#define     FDCMD_STACKDEPTH    16      // up to 1024 byte
    #define     FDCMD_STACKDEPTH    32      // up to 2048 byte
    // header
    uint8_t nextFDwrCmd[FDCMD_STACKDEPTH];
    uint8_t nextFDrdCmd[FDCMD_STACKDEPTH];
    uint8_t nextFDblkNr[FDCMD_STACKDEPTH];
    uint8_t nextFDshort[FDCMD_STACKDEPTH];

    // short data
    uint8_t  nextFDpara1[FDCMD_STACKDEPTH];
    uint8_t  nextFDpara2[FDCMD_STACKDEPTH];
    uint8_t  nextFDpara3[FDCMD_STACKDEPTH];
    uint8_t  nextFDpara4[FDCMD_STACKDEPTH];
    // long data:
    uint8_t longFDlength[FDCMD_STACKDEPTH];
    uint8_t longFDpara[FDCMD_STACKDEPTH][64];

    uint8_t  p_nextFDcmdsInQueue;

    // download of device controller and json files
    struct DCDownload {
        enum class FILE_INDEX {
            DC_BINARY = 0, DC2C_CASH = 1, DC2C_CONF = 2, DC2C_SERIAL=3,
            DC2C_PRINT_01, DC2C_PRINT_02, DC2C_PRINT_03, DC2C_PRINT_04,
            DC2C_PRINT_05, DC2C_PRINT_06, DC2C_PRINT_07, DC2C_PRINT_08,
            DC2C_PRINT_09, DC2C_PRINT_10, DC2C_PRINT_11, DC2C_PRINT_12,
            DC2C_PRINT_13, DC2C_PRINT_14, DC2C_PRINT_15, DC2C_PRINT_16,
            DC2C_PRINT_17, DC2C_PRINT_18, DC2C_PRINT_19, DC2C_PRINT_20,
            DC2C_PRINT_21, DC2C_PRINT_22, DC2C_PRINT_23, DC2C_PRINT_24,
            DC2C_PRINT_25, DC2C_PRINT_26, DC2C_PRINT_27, DC2C_PRINT_28,
            DC2C_PRINT_29, DC2C_PRINT_30, DC2C_PRINT_31, DC2C_PRINT_32
        };
        char m_filename[(int)FILE_INDEX::DC2C_PRINT_32][512];
        std::atomic_ushort m_totalBlocks;
        std::atomic_ushort m_currentblockNumber;
        std::atomic_bool m_requested{false};
        std::atomic_bool m_running{false};
        std::atomic_bool m_finished{false};
    } m_downLoadDC;


    static QSharedMemory *getShm(std::size_t s = 0);

    static SharedMem *getData()
    {
        Q_ASSERT_X(getShm()->data() != nullptr, "pointer access", "nullptr");
        return (SharedMem *)getShm()->data();
    }

    static SharedMem const *getDataConst()
    {
        Q_ASSERT_X(getShm()->data() != nullptr, "pointer access", "nullptr");
        return (SharedMem const *)getShm()->data();
    }

//    static SharedMemBuffer *write()
    static SharedMem *write()
    {
        Q_ASSERT_X(getShm()->data() != nullptr, "pointer access", "nullptr");
        return (SharedMem *)getShm()->data();
    }

//    static SharedMemBuffer const *read()
    static SharedMem const *read()
    {
        Q_ASSERT_X(getShm()->data() != nullptr, "pointer access", "nullptr");
        return (SharedMem const *)getShm()->data();
    }

    bool thisIsTheFirstUse(void);

    #if 0
    static std::atomic<bool> __sharedMemLocked;

    static bool sharedMemLocked() {
        return __sharedMemLocked;
    }
    static void setSharedMemLocked() {
        __sharedMemLocked = true;
    }
    static void setSharedMemUnlocked() {
        __sharedMemLocked = false;
    }
    #endif





};

#endif // SHARED_MEM_BUFFER_INCLUDED_H