#ifndef LWMQTT_HELPERS_H
#define LWMQTT_HELPERS_H

#include "lwmqtt.h"

/**
 * Reads bits from a byte.
 *
 * @param byte The byte to read from.
 * @param pos The position of the first bit.
 * @param num The number of bits to read.
 * @return The read bits as a byte.
 */
uint8_t lwmqtt_read_bits(uint8_t byte, int pos, int num);

/**
 * Write bits to a byte.
 *
 * @param byte The byte to write bits to.
 * @param value The bits to write as a byte.
 * @param pos The position of the first bit.
 * @param num The number of bits to write.
 */
void lwmqtt_write_bits(uint8_t *byte, uint8_t value, int pos, int num);

/**
 * Reads arbitrary data from the specified buffer. The pointer is incremented by bytes read.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param data Pointer to beginning of data.
 * @param len The amount of data to read.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_read_data(uint8_t **buf, const uint8_t *buf_end, uint8_t **data, size_t len);

/**
 * Writes arbitrary data to the specified buffer. The pointer is incremented by the bytes written.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param data Pointer to the to be written data.
 * @param len The amount of data to write.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_write_data(uint8_t **buf, const uint8_t *buf_end, uint8_t *data, size_t len);

/**
 * Reads a two byte number from the specified buffer. The pointer is incremented by two.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param num The read number.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_read_num(uint8_t **buf, const uint8_t *buf_end, uint16_t *num);

/**
 * Writes a two byte number to the specified buffer. The pointer is incremented by two.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param num The number to write.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_write_num(uint8_t **buf, const uint8_t *buf_end, uint16_t num);

/**
 * Reads a string from the specified buffer into the passed object. The pointer is incremented by the bytes read.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param str The object into which the data is to be read.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_read_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t *str);

/**
 * Writes a string to the specified buffer. The pointer is incremented by the bytes written.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param str The string to write.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_write_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t str);

/**
 * Reads one byte from the buffer. The pointer is incremented by one.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param byte The read byte.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_read_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t *byte);

/**
 * Writes one byte to the specified buffer. The pointer is incremented by one.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param byte The byte to write.
 * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
 */
lwmqtt_err_t lwmqtt_write_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t byte);

/**
 * Returns the amount of bytes required by the variable number.
 *
 * @param varnum The number to check.
 * @param len The required length;
 * @return LWMQTT_SUCCESS or LWMQTT_VARNUM_OVERFLOW.
 */
lwmqtt_err_t lwmqtt_varnum_length(uint32_t varnum, int *len);

/**
 * Reads a variable number from the specified buffer. The pointer is incremented by the bytes read.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param varnum The read varnum.
 * @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW.
 */
lwmqtt_err_t lwmqtt_read_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t *varnum);

/**
 * Writes a variable number to the specified buffer. The pointer is incremented by the bytes written.
 *
 * @param buf Pointer to the buffer.
 * @param buf_end Pointer to the end of the buffer.
 * @param varnum The number to write.
 * @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW.
 */
lwmqtt_err_t lwmqtt_write_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t varnum);

#endif
