#ifndef LIBNAGIOS_KVVEC_H_INCLUDED
#define LIBNAGIOS_KVVEC_H_INCLUDED

/**
 * @file kvvec.h
 * @brief Key/value vector library function and type declarations
 *
 * The kvvec library is nifty as either a configuration meta-format
 * or for IPC purposes. Take a look at the buf2kvvec() and kvvec2buf()
 * pair of functions for the latter.
 * @{
 */

/**
 * key/value pair
 * One of the two major components of the kvvec api
 */
struct key_value {
	char *key;     /**< The key */
	char *value;   /**< The value */
	int key_len;   /**< Length of key */
	int value_len; /**< Length of value */
};

/**
 * key/value vector buffer. Actually just a buffer, but one that gets
 * used as return value and internal tracker for kvvec2buf()
 */
struct kvvec_buf {
	char *buf;             /**< The buffer */
	unsigned long buflen;  /**< Length of buffer */
	unsigned long bufsize; /**< Size of buffer (includes overalloc) */
};

/**
 * key/value vector struct
 * This is the main component of the kvvec library
 * @note This should be made opaque, with a kvvec_foreach() using a
 * callback to iterate over key/value pairs.
 */
struct kvvec {
	struct key_value *kv; /**< The key/value array */
	int kv_alloc;         /**< Allocated size of key/value array */
	int kv_pairs;         /**< Number of key/value pairs */
	int kvv_sorted;        /**< Determines if this kvvec has been sorted */
};

/** Portable initializer for stack-allocated key/value vectors */
#define KVVEC_INITIALIZER { NULL, 0, 0, 0 }

/** Parameters for kvvec_destroy() */
#define KVVEC_FREE_KEYS   1 /**< Free keys when destroying a kv vector */
#define KVVEC_FREE_VALUES 2 /**< Free values when destroying a kv vector */
/** Free both keys and values when destroying a kv vector */
#define KVVEC_FREE_ALL    (KVVEC_FREE_KEYS | KVVEC_FREE_VALUES)

#define KVVEC_ASSIGN      0 /**< Assign from buf in buf2kvvec_prealloc() */
#define KVVEC_COPY        1 /**< Copy from buf in buf2kvvec_prealloc() */
#define KVVEC_APPEND      2 /**< Don't reset kvvec in buf2kvvec_prealloc() */

/**
 * Initialize a previously allocated key/value vector
 *
 * @param kvv The key/value vector to initialize
 * @param hint Number of key/value pairs we expect to store
 * @return Pointer to a struct kvvec, properly initialized
 */
extern struct kvvec *kvvec_init(struct kvvec *kvv, int hint);

/**
 * Create a key/value vector
 *
 * @param hint Number of key/value pairs we expect to store
 * @return Pointer to a struct kvvec, properly initialized
 */
extern struct kvvec *kvvec_create(int hint);

/**
 * Resize a key/value vector
 * Used by kvvec_grow(). If size is smaller than the current number of
 * used key/value slots, -1 is returned.
 *
 * @param[in] kvv The key/value vector to resize
 * @param[in] size The size to grow to
 * @return 0 on success, < 0 on errors
 */
extern int kvvec_resize(struct kvvec *kvv, int size);

/**
 * Grow a key/value vector.
 * Used internally as needed by the kvvec api. If 'hint' is zero, the
 * key/value capacity is increased by a third of the current capacity
 * plus a small constant number. This uses kvvec_resize() internally.
 *
 * @param kvv The key/value vector to grow
 * @param hint The amount of key/value slots we should grow by
 * @return 0 on success, < 0 on errors
 */
extern int kvvec_grow(struct kvvec *kvv, int hint);

/**
 * Return remaining storage capacity of key/value vector
 * @param[in] kvv The key/value vector to check
 * @return Number of key/value pairs that can be stored without growing
 */
extern unsigned int kvvec_capacity(struct kvvec *kvv);

/**
 * Sort a key/value vector alphabetically by key name
 * @param kvv The key/value vector to sort
 * @return 0
 */
extern int kvvec_sort(struct kvvec *kvv);

/**
 * Add a key/value pair to an existing key/value vector, with
 * lengths of strings already calculated
 * @param kvv The key/value vector to add this key/value pair to
 * @param key The key
 * @param keylen Length of the key
 * @param value The value
 * @param valuelen Length of the value
 * @return 0 on success, < 0 on errors
 */
extern int kvvec_addkv_wlen(struct kvvec *kvv, const char *key, int keylen, const char *value, int valuelen);

/**
 * Shortcut to kvvec_addkv_wlen() when lengths aren't known
 * @param kvv The key/value vector to add this key/value pair to
 * @param key The key
 * @param value The value
 * @return 0 on success, < 0 on errors
 */
#define kvvec_addkv(kvv, key, value) kvvec_addkv_wlen(kvv, key, 0, value, 0)

/**
 * Walk each key/value pair in a key/value vector, sending them
 * as arguments to a callback function. The callback function has
 * no control over the iteration process and must not delete or
 * modify the key/value vector it's operating on.
 * @param kvv The key/value vector to walk
 * @param arg Extra argument to the callback function
 * @param callback Callback function
 * @return 0 on success, < 0 on errors
 */
extern int kvvec_foreach(struct kvvec *kvv, void *arg, int (*callback)(struct key_value *, void *));

/**
 * Destroy a key/value vector
 * @param kvv The key/value vector to destroy
 * @param flags or'ed combination of KVVEC_FREE_{KEYS,VALUES}, or KVVEC_FREE_ALL
 * @return 0 on success, < 0 on errors
 */
extern int kvvec_destroy(struct kvvec *kvv, int flags);

/**
 * Free key/value pairs associated with a key/value vector
 * @param kvv The key/value vector to operate on
 * @param flags flags or'ed combination of KVVEC_FREE_{KEYS,VALUES}, or KVVEC_FREE_ALL
 */
void kvvec_free_kvpairs(struct kvvec *kvv, int flags);

/**
 * Create a linear buffer of all the key/value pairs and
 * return it as a kvvec_buf. The caller must free() all
 * pointers in the returned kvvec_buf
 * (FIXME: add kvvec_buf_destroy(), or move this and its counterpart
 * out of the kvvec api into a separate one)
 *
 * @param kvv The key/value vector to convert
 * @param kv_sep Character separating keys and their values
 * @param pair_sep Character separating key/value pairs
 * @param overalloc Integer determining how much extra data we should
 *                  allocate. The overallocated memory is filled with
 *                  nul bytes.
 * @return A pointer to a newly created kvvec_buf structure
 */
extern struct kvvec_buf *kvvec2buf(struct kvvec *kvv, char kv_sep, char pair_sep, int overalloc);

/**
 * Create a key/value vector from a pre-parsed buffer. Immensely
 * useful for ipc in combination with kvvec2buf().
 *
 * @param str The buffer to convert to a key/value vector
 * @param len Length of buffer to convert
 * @param kvsep Character separating key and value
 * @param pair_sep Character separating key/value pairs
 * @param flags bitmask. See KVVEC_{ASSIGN,COPY,APPEND} for values
 * @return The created key/value vector
 */
extern struct kvvec *buf2kvvec(char *str, unsigned int len, const char kvsep, const char pair_sep, int flags);

/**
 * Parse a buffer into the pre-allocated key/value vector. Immensely
 * useful for ipc in combination with kvvec2buf().
 *
 * @param kvv A pre-allocated key/value vector to populate
 * @param str The buffer to convert to a key/value vector
 * @param len Length of buffer to convert
 * @param kvsep Character separating key and value
 * @param pair_sep Character separating key/value pairs
 * @param flags bitmask. See KVVEC_{ASSIGN,COPY,APPEND} for values
 * @return The number of pairs in the created key/value vector
 */
extern int buf2kvvec_prealloc(struct kvvec *kvv, char *str, unsigned int len, const char kvsep, const char pair_sep, int flags);
/** @} */
#endif /* INCLUDE_kvvec_h__ */
