#ifndef ARC_STD_CONFIG_H_
#define ARC_STD_CONFIG_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "arc/std/hashtable.h"
#include "arc/std/string.h"
#include <stdint.h>

#define ARC_KEY_BUCKET_SIZE        0x20
#define ARC_GROUP_BUCKET_SIZE      0x20
#define ARC_GROUP_DATA_BUCKET_SIZE 0x20

/**
 * @brief a type that keeps permanice of data for when loading and unloading config files
 */
typedef struct ARC_Config ARC_Config;

/**
 * @brief a function to read a key from string to a ARC_ConfigTypeTemplate
 *
 * @param config ARC_Config to store data to
 * @param string ARC_String of data that is being read in
 * @param value  value that is read in
 *
 * @note use ARC_Config_StoreValue(ARC_Config *config, ARC_String *name, void *value); to store a value to the config
 *       if there is an error, set arc_errno
 * 
 * @return 0 if value not a reference, 1 if value is a reference
 */
typedef uint8_t (* ARC_ConfigKeyRead)(ARC_Config* config, ARC_String *string, void **value);

/**
 * @brief a function to delete a value from a key in ARC_Config
 *
 * @param config  ARC_Config that can be used to check for references in data
 * @param value   pointer of data to be deleted
 *
 * @note this function can be NULL if memory does not need to be cleaned for this type
 *       if there is an error, set arc_errno
 */
typedef void (* ARC_ConfigKeyDelete)(ARC_Config* config, ARC_String *string, void *value);

/**
 * @brief adds a usable key to ARC_Config
 *
 * @param config    ARC_Config to add keys to
 * @param type      string of key type
 * @param keyRead   function for reading/creating key from string
 * @param keyDelete function for deleting stored key
 */
void ARC_Config_AddKey(ARC_Config *config, ARC_String *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete);

/**
 * @brief adds a key from a cstring
 * @param config    ARC_Config to add keys to
 * @param type      cstring of key type
 * @param length    length of cstring
 * @param keyRead   function for reading/creating key from string
 * @param keyDelete function for deleting stored key
*/
void ARC_Config_AddKeyCString(ARC_Config *config, const char *type, uint64_t length, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete);

/**
 * @brief external callback to add keys to config
 */
typedef void (* ARC_ConfigKey_AddFunc)(ARC_Config *config);

/**
 * @brief creates ARC_Config type
 *
 * @param config  ARC_Config to initialize
 */
void ARC_Config_Create(ARC_Config **config);

/**
 * @brief destroys ARC_Config type
 */
void ARC_Config_Destroy(ARC_Config *config);

/**
 * @brief sets current group in config
 *
 * @note ARC_Config_Get will use this set group
 *
 * @param config    ARC_Config we are setting current group in
 * @param groupname name of group that will be set
 */
void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupname);

/**
 * @brief get a value from a given keyname
 *
 * @note name may be prefaced with <group>:: to specify group
 *
 * @param config  ARC_Config to get value from
 * @param keyname name of key to get from config
 * @param value   data retrieved from config
 */
void ARC_Config_Get(ARC_Config *config, ARC_String *keyname, void **value);

/**
 * @brief commands that can be used in ARC_Config_FileIO
 */
#define ARC_CONFIG_FILE_IO_LOAD   0x00
#define ARC_CONFIG_FILE_IO_UNLOAD 0x01

/**
 * @brief handles file io for ARC_Config Type
 *
 * @param config ARC_Config where io operations will take place
 * @param path   file path for io
 */
void ARC_Config_FileIO(ARC_Config *config, ARC_String *path, uint8_t command);

#ifdef __cplusplus
}
#endif

#endif //ARC_STD_CONFIG_H_

#ifdef ARC_DEFAULT_CONFIG
#include "defaults/config.h"
#endif //ARC_DEFAULT_CONFIG
