#ifndef SCPI_CORE_PRIVATE_H
#define SCPI_CORE_PRIVATE_H
#ifdef SCPI_CORE_PRIVATE
   #include "app/fseq/fseq.h"
   #include "app/scpi/scpi_parser.h"
   #include "app/tlst/tree_list.h" // sTreeList_t
   #include "app/scpi/scpi_errq.h"
   #include "app/scpi/scpi_errs.h"
   #include "app/scpi/scpi_gpib_core.h"
   // -----------------------------------------------------------
   // @sScpiParserStateEntry_t
   // SCPI Parser state-machine's state entry:
   // Includes the function-table @entry and the
   // ... state context reference @ctx_ref 
   typedef struct 
   {
      fFSeqEntry_t entry;
      void * const ctx_ref;
   }
   sScpiParserStateEntry_t;

   // -----------------------------------------------------------

   // @DECLARE_SCPI_STATE_ENTRY
   // Declares the state entry to initialize @sScpiCommandHandlerEntry_t 
   #define DECLARE_SCPI_STATE_ENTRY(vtable_, ctx_)\
                             { .entry = { .vtbl = &vtable_ }, .ctx_ref = ctx_ }

   // -----------------------------------------------------------

   // @sScpiCommandHandlerEntry_t
   // SCPI Command handler entry.
   // Links the state machine entry (function-object) and
   // ... the data context together to form the functor-object.
   typedef struct
   {        
       fFSeqEntry_t entry;    // state-machine's state entry
       const void * ctx;      // state's data
   }
   sScpiCommandHandlerEntry_t;

   // -----------------------------------------------------------
   // eScpiParserStateId_t
   // SCPI Parser States
   typedef enum
   {
      eParserResetState,         // restart parser for new SCPI message 
      eSearchForCommandHeader,   // searching for program command header
      eProcessCommandHeader,     // interpreting the command header
      eProcessProgramData,       // processing the command, processing the program data
      eProcessEndOfProgramData,  // end of processing the program data, search message separator
      eHandleError,              // error condition
   }
   eScpiParserStateId_t;

   // -----------------------------------------------------------
   typedef enum
   {
      // ---------------------// Common event codes:
      eScpiEventEmpty,        //  - No event;      
      eScpiEventWrite,        //  - Chunk write / processing (eProcessProgramData);
      eScpiEventRead,         //  - Read chunk / processing (eProcessProgramData);
      eScpiEventRestart,      //  - Restart event
      eScpiEventContinue,     //  - Parse continue event (Error Handle Specific code)
      eScpiEventError,        //  - Special event (exception)
   }
   eScpiEventType_t;
   // -----------------------------------------------------------
   // The following block is disgned to grant exclusive write access to
   // some variables in the common context to prevent modifing by mistake.
   // Some variables marked as 'guarded' using _GUARD_ macro.
   // This means that this variable is only allowed to be modified if a special
   // guarding macro is defined in the module that includes this file. 
   // This guarding macro is different for each file, and the following block can
   // select what file grant the access to.
   #if !defined(SCPI_CORE_C) && !defined(SCPI_RESET_STATE_C)
   #define _GUARD_ const   // all files but excluding 'scpi_core.c' and 'reset_state.c'
   #else
   #define _GUARD_         // only 'scpi_core.c' and 'reset_state.c'
   #endif

   #if !defined(SCPI_END_OF_PROCESS_DATA_C) && !defined(SCPI_PROCESS_DATA_C)
   #define _GUARD_01_ _GUARD_  // all files but excluding 'endof_process_data.c' or 'process_data.c'
   #else
   #define _GUARD_01_          // only 'endof_process_data.c' or 'process_data.c'
   #endif 
                                                               
   #if !defined(SCPI_PROCESS_DATA_C) && !defined(SCPI_HANDLE_ERROR_C) && !defined(SCPI_PROCESS_COMMAND_C) && !defined(SCPI_END_OF_PROCESS_DATA_C)
   #define _GUARD_02_ _GUARD_  // all files but excluding 'process_data.c', 'endof_process_data.c', 'process_command.c' and 'handle_error.c'
   #else
   #define _GUARD_02_          // only 'process_data.c', 'process_command.c' and 'handle_error.c', 'endof_process_data.c'
   #endif

   #if !defined(SCPI_HANDLE_ERROR_C) && !defined(SCPI_END_OF_PROCESS_DATA_C)
   #define _GUARD_03_ _GUARD_  // all files but excluding 'endof_process_data.c' and 'handle_error.c'
   #else
   #define _GUARD_03_          // only 'handle_error.c' and 'endof_process_data.c'
   #endif
   //
   //
   // -----------------------------------------------------------
   // ==============================================================================================
   typedef struct
   {
      struct
      {
          const uint8_t * _GUARD_ pData; // [IN]
          size_t _GUARD_ nDataLength;    // [IN]
      }
      sWrite;
    
      struct
      {
          uint8_t * _GUARD_ pBuffer;     // [IN]
          size_t _GUARD_01_ nBufferSize; // [IN]

          uint8_t * pBufferIdx;          // [IN, OUT]
          size_t nDataLength;            // [IN, OUT], shall be modified by writer

          size_t nTotalLength;           // [IN, OUT], shall be modified by writer
          const void * vLastBufferIdx;   // [OUT]
      }
      sRead;

      struct
      {
        //bool bNewTransfer;             // [IN]
          uint8_t _GUARD_03_ eCode;      // [IN], refer to @eScpiEventType_t
          int8_t eStatus;                // [OUT], refer to @eScpiStatus_t
      }
      sEvent;

      struct
      {
          const uint8_t * pStr;          // [IN, OUT], current iterator in sWrite.pData[]
          const uint8_t * pEnd;          // [IN, OUT], end-of-string in sWrite.pData[]
          bool _GUARD_ w_bEndOfMessage;  // [IN], Write Event
          bool r_bEndOfMessage;          // [IN, OUT], Read Event
          bool bQuery;                   // [IN, OUT]
          bool bLeadResponseSep;         // [IN, OUT] place leading response separator
      }
      sMessage;

      struct
      {
          errq_t xScpiErrorQueue;                                        // SCPI Log queue object
          int runtimeError;                                              // SCPI Error code
          char xScpiErrorMessage[ SCPI_ERRORMSG_MAX ];                   // SCPI Error description
          uint8_t xScpiErrorLogStorage[ SCPI_ERRORLOG_CAPACITY ];        // SCPI Log queue storage buffer
          bool errorQueueOverflow;                                       // Error Queue Overflow indicator
      }
      sExecution;

      struct
      {
          // @xCtxObj: SCPI tokens parser object
          xParseEntry_t xCtxObj; // [IN, OUT]
         
          // @xCmdBranch: SCPI command tree branch
          sTreeList_t * xCmdBranch; // [IN, OUT]
      
          // @xHandler: SCPI command handler entry
          const sScpiCommandHandlerEntry_t * xHandler; // [OUT]

          // @xHandlerToken: linked handler string token
          sStrToken_t xHandlerToken; // [OUT]

          // @xArgToken: current argument token 
          sStrToken_t xArgToken; // [OUT]

          // @bFirstCommandIndicator - the first command in the line indicator
          bool bFirstCommandIndicator; // [IN, OUT]
      }
      sParser;

      struct
      {
          xGPIBRegisters_t registers;
      }
      sGPIB;

      struct
      {
          uint8_t inputCommand[ SCPI_MAX_INPUT_COMMAND ];
          size_t nBytes;
      }
      sCache;
   }
   sScpiParserContext_t;

   // ==============================================================================================
   // @fsq_GetStateById
   // Get the state entry by state identifier @sid
   // @this - current state pointer
   // @sid - the state identifier (eScpiParserStateId_t)
   // Returns: the state entry pointer
   // Note: the caller must be the state from the same entity
   const struct fFSeqEntry_t * fsq_GetStateById( const struct fFSeqEntry_t * this, eScpiParserStateId_t sid );
   // ==============================================================================================
   // @fsq_RaiseError
   // Generate internal error event to place it into SCPI Error Log
   // @scpiError - SCPI error code
   // @msgHandler - optional null-terminated string prefix
   // @msgDescription - optional string message with @msgDescLength length
   // @msgDescriptionEnd - end of optional message string, is used to determine the string length (@msgDescription)
   void fsq_RaiseError( int scpiError, const char * msgHeader, const char * msgDescription, const char * msgDescEnd );
#endif
#endif