/* Copyright (C) 2018 Sam Bazley and Arnau Bigas
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

#ifndef JEJSON_H
#define JEJSON_H

#include <stdio.h>

typedef enum JsonType {
    JSON_STRING,
    JSON_NUMBER,
    JSON_OBJECT,
    JSON_ARRAY,
    JSON_TRUE,
    JSON_FALSE,
    JSON_NULL
} JsonType;

typedef struct JsonString {
    JsonType type;
    void *parent;
    char *data;
} JsonString;

typedef struct JsonNumber {
    JsonType type;
    void *parent;
    double data;
} JsonNumber;

struct JsonPair;
typedef struct JsonPair JsonPair;

typedef struct JsonObject {
    JsonType type;
    void *parent;

    JsonPair *pairs;

    unsigned int used;
    unsigned int size;
} JsonObject;

typedef struct JsonArray {
    JsonType type;
    void *parent;

    void **vals;

    unsigned int used;
    unsigned int size;
} JsonArray;

typedef struct JsonTrueFalseNull {
    JsonType type;
    void *parent;
} JsonTrueFalseNull;

struct JsonPair {
    char *key;
    void *val;
    JsonObject *object;
};

typedef struct JsonError {
    const char *file;
    int line;
    const char *func;
    char *msg;
} JsonError;

void jsonErrorInit(JsonError *err);
void jsonErrorCleanup(JsonError *err);
int jsonErrorIsSet(JsonError *err);

JsonObject *jsonParseFile(const char *path, JsonError *err);
JsonObject *jsonParseString(char *data, JsonError *err);

JsonObject *jsonCreateBaseObject();

void jsonAddString(char *key, char *str, void *parent, JsonError *err);
void jsonAddNumber(char *key, double number, void *parent, JsonError *err);
JsonObject *jsonAddObject(char *key, void *parent, JsonError *err);
JsonArray *jsonAddArray(char *key, void *parent, JsonError *err);
void jsonAddBoolNull(char *key, JsonType type, void *parent, JsonError *err);

void jsonCleanup(JsonObject *obj);

/**
 * Get the type of a generic Json* pointer.
 * @param v The Json* struct to get the type from. This pointer MUST point to
 * a valid Json* object otherwise it will probably throw a segmentation fault.
 * @return The type of parameter v
 */
JsonType jsonGetType(void *v);

/**
 * Checks if object @p obj has a pair with an key equal to @p key.
 * @param obj The object in which to search for the @p key.
 * @param key The key of the pair.
 * @return -1 if the pair was not found, the pair's index otherwise.
 */
int jsonGetPairIndex(JsonObject *obj, const char *key);

/**
 * Get the type of an object's member.
 * @param obj The JsonObject to get the type from. This pointer MUST point to
 * a valid JsonObject.
 * @param key The key of the member from which to get the type
 * @return The type of member key (NULL if obj has no members named key)
 */
JsonType jsonGetMemberType(JsonObject *obj, const char *key);

void jsonGetInt(JsonObject *parent, const char *key, int *num,
        JsonError *err);

void jsonGetUInt(JsonObject *parent, const char *key,
        unsigned int *num, JsonError *err);

void jsonGetBool(JsonObject *parent, const char *key, unsigned int *boolean,
        int nullIsFalse, JsonError *err);

void jsonGetDouble(JsonObject *parent, const char *key, double *d,
        JsonError *err);

void jsonGetFloat(JsonObject *parent, const char *key, float *f,
        JsonError *err);

void jsonGetString(JsonObject *parent, const char *key, char **string,
        JsonError *err);

void jsonGetArray(JsonObject *parent, const char *key, JsonArray **array,
        JsonError *err);

void jsonGetObject(JsonObject *parent, const char *key, JsonObject **obj,
        JsonError *err);

void jsonWriteObject(FILE *file, JsonObject *obj, int indentSize);

#endif /* JEJSON_H */
