#include "arc/std/string.h"
#ifdef ARC_DEFAULT_CONFIG

#include "arc/std/defaults/config.h"

#include "arc/std/array.h"
#include "arc/std/config.h"
#include "arc/std/errno.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void ARC_Defaults_ConfigKey_Create(ARC_Config *config){
    ARC_Config_AddKeyCString(config, "uint8_t"   ,  7, ARC_ConfigKey_Read_Uint8_t    , ARC_ConfigKey_Delete_Uint8_t    );
    ARC_Config_AddKeyCString(config, "int8_t"    ,  6, ARC_ConfigKey_Read_Int8_t     , ARC_ConfigKey_Delete_Int8_t     );
    ARC_Config_AddKeyCString(config, "uint16_t"  ,  8, ARC_ConfigKey_Read_Uint16_t   , ARC_ConfigKey_Delete_Uint16_t   );
    ARC_Config_AddKeyCString(config, "int16_t"   ,  7, ARC_ConfigKey_Read_Int16_t    , ARC_ConfigKey_Delete_Int16_t    );
    ARC_Config_AddKeyCString(config, "uint32_t"  ,  8, ARC_ConfigKey_Read_Uint32_t   , ARC_ConfigKey_Delete_Uint32_t   );
    ARC_Config_AddKeyCString(config, "int32_t"   ,  7, ARC_ConfigKey_Read_Int32_t    , ARC_ConfigKey_Delete_Int32_t    );
    ARC_Config_AddKeyCString(config, "uint64_t"  ,  8, ARC_ConfigKey_Read_Uint64_t   , ARC_ConfigKey_Delete_Uint64_t   );
    ARC_Config_AddKeyCString(config, "int64_t"   ,  7, ARC_ConfigKey_Read_Int64_t    , ARC_ConfigKey_Delete_Int64_t    );
    // ARC_Config_AddKeyCString(config, "char"      ,  4, ARC_ConfigKey_Read_Char       , ARC_ConfigKey_Delete_Char       );
    ARC_Config_AddKeyCString(config, "int"       ,  3, ARC_ConfigKey_Read_Int        , ARC_ConfigKey_Delete_Int        );
    ARC_Config_AddKeyCString(config, "long"      ,  4, ARC_ConfigKey_Read_Long       , ARC_ConfigKey_Delete_Long       );
    ARC_Config_AddKeyCString(config, "float"     ,  5, ARC_ConfigKey_Read_Float      , ARC_ConfigKey_Delete_Float      );
    ARC_Config_AddKeyCString(config, "double"    ,  6, ARC_ConfigKey_Read_Double     , ARC_ConfigKey_Delete_Double     );
    ARC_Config_AddKeyCString(config, "ARC_String", 10, ARC_ConfigKey_Read_String     , ARC_ConfigKey_Delete_String     );
    ARC_Config_AddKeyCString(config, "string[]"  ,  8, ARC_ConfigKey_Read_StringArray, ARC_ConfigKey_Delete_StringArray);
}

uint8_t ARC_ConfigKey_Read_Uint8_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (uint8_t *) malloc(sizeof(uint8_t));
    *((uint8_t *)(*value)) = (uint8_t) ARC_String_ToUint64_t(string);
    return 0;
}


uint8_t ARC_ConfigKey_Read_Int8_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (int8_t *) malloc(sizeof(int8_t));
    *((int8_t *)(*value)) = (int8_t) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Uint16_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (uint16_t *) malloc(sizeof(uint16_t));
    *((uint16_t *)(*value)) = (uint16_t) ARC_String_ToUint64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Int16_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (int16_t *) malloc(sizeof(int16_t));
    *((int16_t *)(*value)) = (int16_t) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Uint32_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (uint32_t *) malloc(sizeof(uint32_t));
    *((uint32_t *)(*value)) = (uint32_t) ARC_String_ToUint64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Int32_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (int32_t *) malloc(sizeof(int32_t));
    *((int32_t *)(*value)) = (int32_t) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Uint64_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (uint64_t *) malloc(sizeof(uint64_t));
    *((uint64_t *)(*value)) = (uint64_t) ARC_String_ToUint64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Int64_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (int64_t *) malloc(sizeof(int64_t));
    *((int64_t *)(*value)) = (int64_t) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Char_t(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    if(string->length != 1){
        arc_errno = ARC_ERRNO_DATA;
        return 0;
    }

    *value = (char *) malloc(sizeof(char));
    *((char *)(*value)) = string->data[0];
    return 0;
}

uint8_t ARC_ConfigKey_Read_Int(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (int *) malloc(sizeof(int));
    *((int *)(*value)) = (int) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Long(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (long *) malloc(sizeof(long));
    *((long *)(*value)) = (long) ARC_String_ToInt64_t(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Float(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (float *) malloc(sizeof(float));
    *((float *)(*value)) = (float) ARC_String_ToDouble(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_Double(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    *value = (double *) malloc(sizeof(double));
    *((double *)(*value)) = (double) ARC_String_ToDouble(string);
    return 0;
}

uint8_t ARC_ConfigKey_Read_String(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    if(string->data[0] != '"' || string->data[string->length - 1] != '"'){
        arc_errno = ARC_ERRNO_DATA;
        ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("in ARC_ConfigKey_Read_String(config, string, value); no matching quotes: %s", string->data);
        return 0;
    }

    ARC_String_CopySubstring((ARC_String **)value, string, 1, string->length - 2);
    return 0;
}

void ARC_ConfigKey_StringArray_ReadString(ARC_Config* config, ARC_String *stripped, uint64_t index, uint64_t length, uint64_t *arrayIndex, void **value){
    ARC_String *substr, *temp;
    ARC_String_CopySubstring(&temp, stripped, index, length);
    ARC_String_StripEndsWhitespace(&substr, temp);
    ARC_String_Destroy(temp);

    // reading in reference
    ARC_String *tempString;
    // ARC_Config_Get(config, substr, (void **) &tempString);
    // if(tempString){
    //     ARC_String_Destroy(substr);

    //     ((ARC_String *)((ARC_Array *) *value)->data)[*arrayIndex] = *tempString;
    //     ++*arrayIndex;

    //     return;
    // }

    //reading in value
    ARC_ConfigKey_Read_String(config, substr, (void **) &tempString);
    if(arc_errno){
        ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("in ARC_RectArray_ReadRect(config, string, index, length, arrayIndex, value); failed to read string: %s", substr->data);
        ARC_String_Destroy(substr);
        return;
    }

    ((ARC_String **)((ARC_Array *) *value)->data)[*arrayIndex] = tempString;
    ++*arrayIndex;

    ARC_String_Destroy(substr);
}

uint8_t ARC_ConfigKey_Read_StringArray(ARC_Config* config, ARC_String *string, void **value){
    ARC_Config_Get(config, string, value);
    if(*value){
        return 1;
    }

    if(string->data[0] != '{' || string->data[string->length - 1] != '}'){
        arc_errno = ARC_ERRNO_DATA;
        ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("in ARC_ConfigKey_Read_StringArray(config, string, value); no matching curly braces: %s", string->data);
        return 0;
    }

    ARC_String *temp, *stripped;
    ARC_String_CopySubstring(&temp, string, 1, string->length - 2);
    ARC_String_StripEndsWhitespace(&stripped, temp);
    ARC_String_Destroy(temp);

    uint64_t arraySize = 1;
    for(uint64_t i = 0; i < stripped->length; i++){
        if(stripped->data[i] == ','){
            arraySize++;
        }
    }
    
    *value = malloc(sizeof(ARC_Array));
    ((ARC_Array *) *value)->data = malloc(sizeof(ARC_String *) * arraySize);
    ((ARC_Array *) *value)->size = arraySize;

    uint64_t index = 0;
    arraySize = 0;
    for(uint64_t i = 0; i < stripped->length; i++){
        if(stripped->data[i] == ','){
            ARC_ConfigKey_StringArray_ReadString(config, stripped, index, i - index, &arraySize, value);
            if(arc_errno){
                return 0;
            }

            index = i + 1;

            if(arraySize == ((ARC_Array *) *value)->size){
                break;
            }
        }
    }

    if(arraySize != ((ARC_Array *) *value)->size){
        ARC_ConfigKey_StringArray_ReadString(config, stripped, index, stripped->length - index, &arraySize, value);
    }
    ARC_String_Destroy(stripped);
    return 0;
}



void ARC_ConfigKey_Delete_Uint8_t(ARC_Config *config, ARC_String *string, void *value){
    free((uint8_t *)value);
}

void ARC_ConfigKey_Delete_Int8_t(ARC_Config *config, ARC_String *string, void *value){
    free((int8_t *)value);
}

void ARC_ConfigKey_Delete_Uint16_t(ARC_Config *config, ARC_String *string, void *value){
    free((uint16_t *)value);
}

void ARC_ConfigKey_Delete_Int16_t(ARC_Config *config, ARC_String *string, void *value){
    free((int16_t *)value);
}

void ARC_ConfigKey_Delete_Uint32_t(ARC_Config *config, ARC_String *string, void *value){
    free((uint32_t *)value);
}

void ARC_ConfigKey_Delete_Int32_t(ARC_Config *config, ARC_String *string, void *value){
    free((int32_t *)value);
}

void ARC_ConfigKey_Delete_Uint64_t(ARC_Config *config, ARC_String *string, void *value){
    free((uint64_t *)value);
}

void ARC_ConfigKey_Delete_Int64_t(ARC_Config *config, ARC_String *string, void *value){
    free((int64_t *)value);
}

void ARC_ConfigKey_Delete_Char(ARC_Config *config, ARC_String *string, void *value){
    free((char *)value);
}

void ARC_ConfigKey_Delete_Int(ARC_Config *config, ARC_String *string, void *value){
    free((int *)value);
}

void ARC_ConfigKey_Delete_Long(ARC_Config *config, ARC_String *string, void *value){
    free((long *)value);
}

void ARC_ConfigKey_Delete_Float(ARC_Config *config, ARC_String *string, void *value){
    free((float *)value);
}

void ARC_ConfigKey_Delete_Double(ARC_Config *config, ARC_String *string, void *value){
    free((double *)value);
}

void ARC_ConfigKey_Delete_String(ARC_Config *config, ARC_String *string, void *value){
    ARC_String_Destroy((ARC_String *)value);
}

void ARC_ConfigKey_Delete_StringArray(ARC_Config *config, ARC_String *string, void *value){
    for(uint32_t i = 0; i < ((ARC_Array *)value)->size; i++){
        free(((ARC_String **)((ARC_Array *)value)->data)[i]);
    }
    free((ARC_Array *)value);
}

#endif //ARC_DEFAULT_CONFIG
