#include <stdio.h>

#define SCPI_ARGS_N 0
#include "app/scpi/scpi_handler.h"

#include "app/scpi/commandHandlers/syst_error.h"
#include "app/nfm/nfm_base.h"

//----------------------------------------------------------------
// Refer to:
// [1] SCPI Specification, revision 1999.0
//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
//----------------------------------------------------------------
// Refer "21.8.1 The Error/Event Queue", [1]
// Refer "8.2.2 System sub-system", [2]
// =================================================================================
// @fsqvbl_CommandHandlerSystemError
// State's virtual table

static void fsqe_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
static void fsql_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );

const fFSeqVTable_t fsqvbl_CommandHandlerSystemError = 
{
     .f = fsqf_CommandHandlerSystemError,
     .enter = fsqe_CommandHandlerSystemError,  
     .leave = fsql_CommandHandlerSystemError
};

static void fsqe_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
{    
    sProcessProgramDataCommonContext_t * common_ctx = ctx;

    common_ctx->SYSTemERRor.idx = 0; // reset position
    common_ctx->SYSTemERRor.error = false;
}

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

static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemError( const struct fFSeqEntry_t * this, 
                                                            tFSeqCtx_t ctx, 
                                                             const struct fFSeqEntry_t * * pDeferredNext )
{
    const fFSeqEntry_t * nextstate = NULL;

    sProcessProgramDataCommonContext_t * common_ctx = ctx;
    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;

    switch( common_ctx->event )
    {
        case eProgramData_Event_Write:
        {
            if( ! common_ctx->isQuery )
            {
               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
            }
            else
            {
               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
               (void)nextstate; // stay in this state
            }
        }
        break;

        case eProgramData_Event_Read:
        {
             // @idx - current position of the source data to be outputed
             if( common_ctx->SYSTemERRor.idx == 0 ) // first reading
             {
                 int16_t scpiError;
                 size_t len = sizeof( global_ctx->sExecution.xScpiErrorMessage );

                 // Check overflow flag ("21.8.1 The Error/Event Queue", [1], "8.2.2 System sub-system", [2])
                 if( global_ctx->sExecution.errorQueueOverflow )
                 {
                     // Form 'Overflow' error without placing it into the queue
                     fsq_RaiseError( SCPI_ERROR_QUEUE_OVERFLOW,
                                     SCPI_ERROR_QUEUE_OVERFLOW_MSG, 
                                     NULL, NULL );

                     (void)global_ctx->sExecution.xScpiErrorMessage; // use formatted message text

                     global_ctx->sExecution.errorQueueOverflow = false; // reset overflow indicator
                 }
                 else
                 // Note: function @fsq_RaiseError uses the same buffer to place the error message to the log
                 // So it guarantees that any message placed into the log can be extracted to the same buffer:
                 //  @global_ctx->sExecution.xScpiErrorMessage
                 if( !errq_isempty(&global_ctx->sExecution.xScpiErrorQueue) 
                   && errq_peek( &global_ctx->sExecution.xScpiErrorQueue,
                            &scpiError,
                            &global_ctx->sExecution.xScpiErrorMessage[0],
                            &len) )
                 {
                     errq_removetop( &global_ctx->sExecution.xScpiErrorQueue );
                 }
                 else
                 {
                     strcpy( global_ctx->sExecution.xScpiErrorMessage,
                             SCPI_ERROR_NO );
                 }

                 // check if the error queue is empty
                 if( errq_isempty(&global_ctx->sExecution.xScpiErrorQueue) )
                 {
                     // clear EAV bit in GPIB
                     GPIBMachine.fGPIB_set_error_available_bit( &global_ctx->sGPIB.registers, false );
                 }
             }

             // Since @done flag is set, this dispatcher shall not be called anymore.
             // Since this handler is implemented as a single-state automat, there no
             // ... other states to go to:
             (void)nextstate;

             // modify current postion index:
             SCPI_RESPONSE_HELPER_EX( common_ctx, common_ctx->SYSTemERRor.idx, global_ctx->sExecution.xScpiErrorMessage, sizeof(global_ctx->sExecution.xScpiErrorMessage) );
        }
        break;
    }

    return nextstate;
}

