// Author: Sychov. A / 12/2020
#include "app/queue/queue_ex.h"
  
int queue_pushback_payload(queue_t * self, queue_record_t * record, const void * payload )
{
    assert(self);
    assert(record);
    assert((int)record->size >= (int)record->payload + (int)sizeof(queue_record_t));
                
    // [ queue record header ][ some data ][ payload ]
    // |<-- queue_record_t ->|             |< size  >|
    // |<-------------- record->size --------------->|

    int freeSpace = ringbuf_free_space(self);
    if(freeSpace < record->size)
    {
        return QUEUE_RC_NO_MEMORY;
    }

    // place common header
    int16_t rc = ringbuf_write(self, (void *)record, record->size - record->payload);
    assert((int)record->size - (int)record->payload == (int)rc);
    (void)rc;

    // place payload
    rc = ringbuf_write(self, (void *)payload, record->payload);
    assert(record->payload == rc);
    (void)rc;

    return QUEUE_RC_NOERROR;
}

int queue_peek_payload(const queue_t * self, queue_record_t * record, int16_t recordBufferSize, void * payload, int16_t payloadBufferSize )
{
    assert(self);
    assert(record);
    assert((int)sizeof(*record) <= recordBufferSize);

    if( sizeof(*record) > recordBufferSize)
    {
       return QUEUE_RC_NO_MEMORY;
    }

    // [ queue record header ][ some data ][ payload ]
    // |<-- queue_record_t ->|             |< size  >|
    // |<-------------- record->size --------------->|

    int rc = ringbuf_peek(self, (void *)record, sizeof(*record));
    assert(sizeof(*record) == rc);
    if(sizeof(*record) != rc)
    {
        return QUEUE_RC_EMPTY;
    }

    assert(record->payload + sizeof(*record) <= record->size );
    assert(record->size <= ringbuf_size(self));
    assert(record->size >= sizeof(*record));
  //assert(record->size <= recordBufferSize + payloadBufferSize );
  //assert(record->payload <= payloadBufferSize );

    if( (record->payload > record->size + sizeof(*record)) || record->size < sizeof(*record) )
    {
        return QUEUE_RC_INTERNAL_ERROR;
    }

    if( payloadBufferSize > record->payload )
    {
        payloadBufferSize = record->payload;
    }

    if( recordBufferSize > record->size - record->payload )
    {
        recordBufferSize = record->size - record->payload;
    }

    rc = ringbuf_peek(self, (void *)record, recordBufferSize);
    assert(recordBufferSize == rc);
    if(recordBufferSize != rc)
    {
        return QUEUE_RC_INTERNAL_ERROR;
    }
    
    if( payloadBufferSize > 0 )
    {   
        assert(payload);
        if( NULL != payload )
        {
            int prc = ringbuf_peek_offset(self, (void *)payload, payloadBufferSize, (record->size - record->payload) );  // payload offset
            assert(payloadBufferSize == prc);
            if(payloadBufferSize != prc)
            {
                return QUEUE_RC_INTERNAL_ERROR;
            }

            rc += prc;
        }
    }

    return rc;
}
#if 0
int queue_peek_n(const queue_t * self, queue_record_t * record, int16_t partSize)
{
    // Reading t struct first and getting size of whole
    // record struct. Then reading a part of record struct.
    assert(self);
    assert(record);
    assert((int)sizeof(*record) <= partSize);

    int rc = ringbuf_peek(self, (void *)record, sizeof(*record));
    assert(sizeof(*record) == rc);
    if(sizeof(*record) != rc)
    {
        return QUEUE_RC_EMPTY;
    }

    assert(record->size <= ringbuf_size(self));
    if( partSize > record->size )
    {
        partSize = record->size;
    }

    rc = ringbuf_peek(self, (void *)record, partSize);
    assert(partSize == rc);
    if(partSize != rc)
    {
        return QUEUE_RC_INTERNAL_ERROR;
    }

    return partSize;
}
#endif
