#pragma once
#include <stdint.h>
#include <cstdlib>

typedef struct {
	uint8_t*	first_segment_address;
    size_t 		first_segment_length;
    uint8_t*	second_segment_address;
    size_t		second_segment_length;
} buffers_t;

class RingBuffer
{

	public:
		// Allocates a ringbuffer data structure of a specified size. The
		// caller must arrange for a call to jack_ringbuffer_free() to release
		// the memory associated with the ringbuffer.

		RingBuffer(size_t size);

		// Frees the ringbuffer data structure allocated by an earlier call to
		// constructor.

		~RingBuffer();

		//	Fill a data structure with a description of the current readable
		// data held in the ringbuffer.  This description is returned in a two
		// element array of jack_ringbuffer_data_t.  Two elements are needed
		// because the data to be read may be split across the end of the
		// ringbuffer.

		// The first element will always contain a valid @a len field, which
		// may be zero or greater.  If the @a len field is non-zero, then data
		// can be read in a contiguous fashion using the address given in the
		// corresponding @a buf field.

		// If the second element has a non-zero @a len field, then a second
		// contiguous stretch of data can be read from the address given in
		// its corresponding @a buf field.


		void ReadVector(buffers_t& buffers);

		// Fill a data structure with a description of the current writable
		// space in the ringbuffer.  The description is returned in a two
		// element array of buffers_t.  Two elements are needed
		// because the space available for writing may be split across the end
		// of the ringbuffer.

		// The first element will always contain a valid @a len field, which
		// may be zero or greater.  If the @a len field is non-zero, then data
		// can be written in a contiguous fashion using the address given in
		// the corresponding @a buf field.

		// If the second element has a non-zero @a len field, then a second
		// contiguous stretch of data can be written to the address given in
		// the corresponding @a buf field.
		void WriteVector(buffers_t& buffers);

		// Read data from the ring buffer.
		size_t Read(uint8_t *dest, size_t cnt);

		// Read data from the ring buffer. Opposed to jack_ringbuffer_read()
		// this function does not move the read pointer. Thus it's
		// convenient way to inspect data in the ring buffer in a continuous fashion.
		size_t Peek(uint8_t *dest, size_t cnt);

		// Advance the read pointer.
		void ReadAdvance(size_t cnt);

		size_t ReadSpace(void);

		// Lock a ring buffer data block into physical memory.
		bool Lock(void);

		// Reset the internal "available" size, and read and write pointers, making an empty buffer.
		// This is not thread safe.
		void Reset(void);

		// Write data into the ring buffer.
		size_t Write(const uint8_t *src, size_t cnt);

		// Advance the write pointer, freeing room for future read operations
		void WriteAdvance(size_t cnt);

		// Return the number of bytes available for writing.
		size_t WriteSpace(void);

	private:

	    uint8_t*			m_Buffer;
	    volatile size_t 	m_Write;
	    volatile size_t 	m_Read;
	    size_t				m_Size;
	    size_t				m_SizeMask;
	    bool				m_Locked;
};
