#define SCPI_CORE_STATE__ENDOFDATAPROCESSING_GUARD
#include "app/scpi/CommandParserStates/handle_error.h"
#define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
#define SCPI_END_OF_PROCESS_DATA_C  // access to some const variables in 'scpi_core_private.h'
#include "app/scpi/scpi_core_private.h"

// =================================================================================
// @sEndOfDataProcessingContext_t
// State's private context typedef
typedef struct
{ 
   bool bKeepParserContext;
}
sEndOfDataProcessingContext_t;

// =================================================================================
// @ctx_EndOfDataProcessing
// State's private context
sEndOfDataProcessingContext_t ctx_EndOfDataProcessing;

// =================================================================================
// @fsqvbl_EndOfDataProcessing
// State's virtual table

static void fsqe_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
static void fsql_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
static const struct fFSeqEntry_t * fsqf_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pnext );

const fFSeqVTable_t fsqvbl_EndOfDataProcessing = 
{
     .f = fsqf_EndOfDataProcessing,
     .enter = fsqe_EndOfDataProcessing,  
     .leave = fsql_EndOfDataProcessing
};

static void fsqe_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
{
     sScpiParserContext_t * global_ctx = ctx;
     sEndOfDataProcessingContext_t * private_ctx = fsq_GetPrivateCtxRef(this);

     // init keep-parser-context indicator
     private_ctx->bKeepParserContext = false;

    (void)global_ctx;
}

static void fsql_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
{
     
}

static const struct fFSeqEntry_t * fsqf_EndOfDataProcessing( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pnext )
{
     sScpiParserContext_t * global_ctx = ctx;
     sEndOfDataProcessingContext_t * private_ctx = fsq_GetPrivateCtxRef(this);

     const fFSeqEntry_t * nextstate = fsq_GetStateById(this,eHandleError); // go next state: eHandleError by default 

     switch( global_ctx->sEvent.eCode )
     {
        case eScpiEventRestart:
        {
            // go to reset state
            nextstate = fsq_GetStateById(this,eParserResetState);
        }
        break;

        case eScpiEventError:         // Transport error.
        {
            // Enter error state
            nextstate = fsq_GetStateById(this,eHandleError); // enter the error state            
        }
        break;

        case eScpiEventWrite:
        case eScpiEventRead:
        {
            nextstate = NULL; // stay in current state

            if( eScpiStatus_failed == global_ctx->sEvent.eStatus )
            {
                // Enter error state
                fsq_RaiseError( SCPI_ERROR_STATE, NULL, NULL, 0 );

                nextstate = fsq_GetStateById(this,eHandleError); // enter the error state
            }
            else if ( 
              (eScpiStatus_need_data == global_ctx->sEvent.eStatus) 
              && 
              (eScpiEventWrite == global_ctx->sEvent.eCode)
            )
            {
               private_ctx->bKeepParserContext = true;  // keep parser context til next call

               nextstate = NULL; // NULL, do not change state
            }
            else
            {
                // Retrieve the last parsed entity tail and 
                // ... update current input buffer iterator @sMessage.pStr
                getParsedEntityDetails( &(global_ctx->sParser.xCtxObj), NULL,
                      (void const**)&global_ctx->sMessage.pStr, NULL );

                // Is there unprocessed command in input buffer?
                if( ((ptrdiff_t)global_ctx->sMessage.pEnd - (ptrdiff_t)global_ctx->sMessage.pStr) > 0 )
                {
                    (void)global_ctx->sEvent.eCode;
                    global_ctx->sEvent.eStatus = eScpiStatus_need_data; // reset status code
                    (void)global_ctx->sWrite.pData;
                    (void)global_ctx->sWrite.nDataLength;
                    (void)global_ctx->sMessage.w_bEndOfMessage;
                    global_ctx->sMessage.r_bEndOfMessage = false;
                    global_ctx->sMessage.bQuery = false;
                    (void)global_ctx->sMessage.pStr;
                    (void)global_ctx->sMessage.pEnd;
                    (void)global_ctx->sRead.nTotalLength; // see scpi_WriteChunkOutput
                    (void)global_ctx->sRead.pBufferIdx; // see scpi_WriteChunkOutput
                    (void)global_ctx->sRead.nBufferSize; // see scpi_WriteChunkOutput
                    global_ctx->sMessage.bLeadResponseSep = (global_ctx->sRead.vLastBufferIdx != global_ctx->sRead.pBufferIdx);
                    global_ctx->sRead.vLastBufferIdx = global_ctx->sRead.pBufferIdx; // remember the pointer value before the next command

                    nextstate = fsq_GetStateById(this,eSearchForCommandHeader); // try to parse the rest part of data
                }
                else
                {
                    // go to idle state: endof_process_data + eScpiEventEmpty
                    global_ctx->sEvent.eCode = eScpiEventEmpty;
                    (void)global_ctx->sMessage.r_bEndOfMessage;
                    nextstate = this; // stay this state and recall it now
                }
            }

            // "6.1.10.2.1 Message Available Message (MAV)", [1]
            // The state changed to 'endof_process_data' as far as all the data has been send to host
            // Reset Message Available indicator
            scpi_UpdateMessageAvailable();
        }
        break;

        case eScpiEventEmpty:         // idle state
        {
            // Respond with empty string:
            if( global_ctx->sRead.nDataLength == 0 ) // no response in output buffer
            if( global_ctx->sRead.nBufferSize >= 1 ) // there is vacant room in output buffer
            {
               scpi_WriteCharOutput( ' ' );
            }
            
            scpi_UpdateMessageAvailable();

            global_ctx->sMessage.r_bEndOfMessage = true; // no more data available
            global_ctx->sEvent.eStatus = eScpiStatus_success;
            nextstate = NULL; // stay this state
        }
        break;
     }
     
     return nextstate;
}