

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#ifndef __JSMN_H_
#define __JSMN_H_

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#define JSMN_PARENT_LINKS

#include "Utils.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * JSON type identifier. Basic types are:
 * 	o Object
 * 	o Array
 * 	o String
 * 	o Other primitive: number, boolean (true/false) or null
 */
typedef enum {
	JSMN_UNDEFINED = 0,
	JSMN_OBJECT = 1,
	JSMN_ARRAY = 2,
	JSMN_STRING = 3,
	JSMN_PRIMITIVE = 4
} jsmntype_t;

enum jsmnerr {
	/* Not enough tokens were provided */
	JSMN_ERROR_NOMEM = -1,
	/* Invalid character inside JSON string */
	JSMN_ERROR_INVAL = -2,
	/* The string is not a full JSON packet, more bytes expected */
	JSMN_ERROR_PART = -3
};

/**
 * JSON token description.
 * @param		type	type (object, array, string etc.)
 * @param		start	start position in JSON data string
 * @param		end		end position in JSON data string
 */
typedef struct {
	jsmntype_t type;
	int start;
	int end;
	int size;
#ifdef JSMN_PARENT_LINKS
	int parent;
#endif
} jsmntok_t;

/**
 * JSON parser. Contains an array of token blocks available. Also stores
 * the string being parsed now and current position in that string
 */
typedef struct {
	unsigned int pos; /* offset in the JSON string */
	unsigned int toknext; /* next token to allocate */
	int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;

/**
 * Create JSON parser over an array of tokens
 */
void jsmn_init(jsmn_parser *parser);

/**
 * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
 * a single JSON object.
 */
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
		jsmntok_t *tokens, unsigned int num_tokens);

#ifdef __cplusplus
}
#endif


int GetJSONTokenLevel(jsmntok_t *tokens, int startToken);

const char* GetJSONValue(jsmntok_t* tokens, int tokenCount, const char* json, int token, int &valLength);
std::string GetJSONValueString(jsmntok_t* tokens, int tokenCount, const char* json, int token);
int64 GetJSONValueInt64(jsmntok_t* tokens, int tokenCount, const char* json, int token);
uint64 GetJSONValueUint64(jsmntok_t* tokens, int tokenCount, const char* json, int token);
float64 GetJSONValueFloat64(jsmntok_t* tokens, int tokenCount, const char* json, int token);

int GetJSONToken(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);

const char* GetJSONValue(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type, int &valLength, int level = 0, int instance = 0);
std::string GetJSONValueString(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type = JSMN_UNDEFINED, int level = 0, int instance = 0);
int64 GetJSONValueInt64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type = JSMN_UNDEFINED, int level = 0, int instance = 0);
uint64 GetJSONValueUint64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type = JSMN_UNDEFINED, int level = 0, int instance = 0);
float64 GetJSONValueFloat64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type = JSMN_UNDEFINED, int level = 0, int instance = 0);

const char* GetJSONChildValue(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type, int &valLength);
std::string GetJSONChildValueString(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);
int64 GetJSONChildValueInt64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);
uint64 GetJSONChildValueUint64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);
float64 GetJSONChildValueFloat64(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);

std::vector<int> GetJSONArrayIndexes(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, jsmntype_t type = JSMN_UNDEFINED, int level = 0, int instance = 0);
std::vector<int> GetJSONChildArrayIndexes(jsmntok_t* tokens, int tokenCount, const char* json, const char* key, int parent, jsmntype_t type = JSMN_UNDEFINED);
std::vector<int> GetJSONChildArrayIndexes(jsmntok_t* tokens, int tokenCount, const char* json, int parent, jsmntype_t type = JSMN_UNDEFINED);


#endif /* __JSMN_H_ */

// Example
//
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include "../jsmn.h"
//
///*
// * A small example of jsmn parsing when JSON structure is known and number of
// * tokens is predictable.
// */
//
//const char *JSON_STRING =
//	"{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n  "
//	"\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}";
//
//static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
//	if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
//			strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
//		return 0;
//	}
//	return -1;
//}
//
//int main() {
//	int i;
//	int r;
//	jsmn_parser p;
//	jsmntok_t t[128]; /* We expect no more than 128 tokens */
//
//	jsmn_init(&p);
//	r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0]));
//	if (r < 0) {
//		printf("Failed to parse JSON: %d\n", r);
//		return 1;
//	}
//
//	/* Assume the top-level element is an object */
//	if (r < 1 || t[0].type != JSMN_OBJECT) {
//		printf("Object expected\n");
//		return 1;
//	}
//
//	/* Loop over all keys of the root object */
//	for (i = 1; i < r; i++) {
//		if (jsoneq(JSON_STRING, &t[i], "user") == 0) {
//			/* We may use strndup() to fetch string value */
//			printf("- User: %.*s\n", t[i+1].end-t[i+1].start,
//					JSON_STRING + t[i+1].start);
//			i++;
//		} else if (jsoneq(JSON_STRING, &t[i], "admin") == 0) {
//			/* We may additionally check if the value is either "true" or "false" */
//			printf("- Admin: %.*s\n", t[i+1].end-t[i+1].start,
//					JSON_STRING + t[i+1].start);
//			i++;
//		} else if (jsoneq(JSON_STRING, &t[i], "uid") == 0) {
//			/* We may want to do strtol() here to get numeric value */
//			printf("- UID: %.*s\n", t[i+1].end-t[i+1].start,
//					JSON_STRING + t[i+1].start);
//			i++;
//		} else if (jsoneq(JSON_STRING, &t[i], "groups") == 0) {
//			int j;
//			printf("- Groups:\n");
//			if (t[i+1].type != JSMN_ARRAY) {
//				continue; /* We expect groups to be an array of strings */
//			}
//			for (j = 0; j < t[i+1].size; j++) {
//				jsmntok_t *g = &t[i+j+2];
//				printf("  * %.*s\n", g->end - g->start, JSON_STRING + g->start);
//			}
//			i += t[i+1].size + 1;
//		} else {
//			printf("Unexpected key: %.*s\n", t[i].end-t[i].start,
//					JSON_STRING + t[i].start);
//		}
//	}
//	return 0;
//} 
