/***********************************************************
* Copyright (C), 2021, LuxShare co.,
*
* File name : lux_json_api
*
* Description :
* 	JSON API
*
* History:
*
* <Date> 		<Author> 	<version> 	<Modification>
* 2021/04/21		Laurence Zhou 	 0.01 		First draft
***********************************************************/

#include "lux_json_api.h"

/***********************************************************
* Name:
*	LuxcJSONParseJsonFile
*
* Summary:
*       parse JSON file to get the HEAD pointer(note: remeber to call Luxcjsondelete() to free memory)
*
* Return Value:
*	The LuxcJSONParseJsonFile() function returns a HEAD pointer to HEAD node of the Doubly Linked List 
*
* Parameter Input:
*	char* pcFileName -- JSON file name with Absolute path
*
* Parameter Output:
*	None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/

cJSON* LuxcJSONParseJsonFile(char* pcFileName)
{
    long lLen = 0;
    char* psBuf = NULL;
    cJSON* psRoot = NULL;
    if(NULL == pcFileName)
    {
	return NULL;
    }
    FILE* fp = LuxFopen(pcFileName, "rb+");
    if (NULL == fp)
    {
	printf("open file %s failed.\n", pcFileName);
	return NULL;
    }
    LuxFseek(fp, 0, SEEK_END);
    lLen = LuxFtell(fp);
    if (0 == lLen)
    {
	return NULL;
    }
    LuxFseek(fp, 0, SEEK_SET);
    psBuf = (char *)LuxMalloc(sizeof(char) * lLen);
    LuxFread(psBuf, 1, lLen, fp);
    LuxFclose(fp);
    cJSON_Minify(psBuf);
    psRoot = cJSON_Parse(psBuf);
    if (NULL == psRoot)
    {
	return NULL;
    }
    LuxFree(psBuf);
    return psRoot;
}

/***********************************************************
* Name:
*	LuxcJSONPrint
*
* Summary:
*        Render a cJSON entity to text for transfer/storage(note: remeber to call Luxcjsonfree to free memory)
*
* Return Value:
*	a string 
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*
* Parameter Output:
*	None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
char* LuxcJSONPrint(const cJSON* psItem)
{
    if(NULL != psItem)
    {
	return cJSON_Print(psItem);
    }
    return NULL;
}

/***********************************************************
* Name:
*	LuxcJSONGetObjectItem
*
* Summary:
*        Get item "pcKey" from psObject
*
* Return Value:
*	Pointer to the "pcKey" cJSON node
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*
* Parameter Output:
*	None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
**********************************************************/
cJSON* LuxcJSONGetObjectItem(const cJSON* const psObject, const char* const pcKey)
{
    if(NULL == psObject)
    {
	return NULL;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return NULL;
    }
    if(NULL == pcKey)
    {
	return NULL;
    }
    cJSON* psTemp = NULL;
    psTemp = cJSON_GetObjectItem(psObject, pcKey);
    if (psTemp)
    {
	return psTemp;
    }
    else
    {
	return NULL;
    }
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectIntValue
*
* Summary:
*        Get int value
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        int* piValue -- Pointer that holds the int value
*
* Parameter Output:
*	piVAlue
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectIntValue(const cJSON* const psObject, const char* const pcKey,int* piValue )
{
    cJSON* psItem = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piValue)
    {
	return FUNC_FAILED;
    }
    if( NULL == (psItem = (cJSON_GetObjectItem(psObject, pcKey))))
    {
	return FUNC_FAILED;
    }
  
    *piValue = psItem->valueint;
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectDoubleValue
*
* Summary:
*        Get double value
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        double* pdValue -- Pointer that holds the double value
*
* Parameter Output:
*	pdValue
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectDoubleValue(const cJSON* const psObject,const char* const pcKey, double* pdValue)
{
    cJSON* psItem = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == pdValue)
    {
	return FUNC_FAILED;
    }
    if(NULL == (psItem = (cJSON_GetObjectItem(psObject, pcKey))))
    {
	return FUNC_FAILED;
    }
      
    *pdValue = psItem->valuedouble;
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectStringSize
*
* Summary:
*        Get the length of String 
*
* Return Value:
*	 length of String
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*
* Parameter Output:
*	None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetOjectStringSize(const cJSON* const psObject, const char* const pcKey, int *piSize)
{
    cJSON* psItem = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piSize)
    {
	return FUNC_FAILED;
    }
    psItem = cJSON_GetObjectItem(psObject, pcKey);
    *piSize = LuxStrlen(psItem->valuestring);
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectStringValue
*
* Summary:
*        Get string value
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        char* pcValue -- Pointer that holds the String value
*
* Parameter Output:
*	pcValue
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectStringValue(const cJSON* const psObject, const char* const pcKey, char* pcValue )
{
    cJSON* psItem = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == pcValue)
    {
	return FUNC_FAILED;
    }
    if(NULL == (psItem=(cJSON_GetObjectItem(psObject, pcKey))))
    {
	return FUNC_FAILED;
    }
    LuxStrcpy(pcValue,psItem->valuestring);
    return FUNC_OK;


}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectBooleanValue
*
* Summary:
*        Get boolean value
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psItem -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        cJSON_bool* pbValue -- Pointer that holds the boolean value
*
* Parameter Output:
*	pbValue
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectBooleanValue(const cJSON* const psObject, const char* const pcKey, cJSON_bool* pbValue)
{
    cJSON* psItem = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == pbValue)
    {
	return FUNC_FAILED;
    }
    if(NULL == (psItem = cJSON_GetObjectItem(psObject, pcKey)))
    {
	return FUNC_FAILED;
    }
    
    if(false == psItem->valueint)
    {  
	*pbValue = false;
	return FUNC_OK;
    }
    else
    {
	*pbValue = true;
	return FUNC_OK;
    }
    
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectArraySize
*
* Summary:
*        Get the array size
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        int* piSize -- Pointer that holds the array size
*
* Parameter Output:
*	piSize
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectArraySize(const cJSON* const psObject, const char* const pcKey, int* piSize)
{
    cJSON* psArray = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piSize)
    {
	return FUNC_FAILED;
    }
    if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
    {
	return FUNC_FAILED;
    }
    *piSize =  cJSON_GetArraySize(psArray);
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectIntArray
*
* Summary:
*        Get the int array
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        int* piArray -- Pointer that holds the int array(if pass NULL to piArray,we can get the array size)
*        int* piSize -- Pointer that holds the array size
*
* Parameter Output:
*	piArray,piSize
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectIntArray(const cJSON* const psObject, const char* const pcKey, int* piArray,int* piSize)  
{
    cJSON *psArray = NULL;
    cJSON *psTemp = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piSize)
    {
	return FUNC_FAILED;
    }
    if(NULL == piArray )
    {
	if(FUNC_OK == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_OK;
	}
    }
    else
    {
	if(FUNC_FAILED == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_FAILED;
	}
    
	if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
	{
	    return FUNC_FAILED;
	}
	
	for (int i = 0,j = 0; i < *piSize && j < *piSize; ++i,++j)
	{
	    psTemp = cJSON_GetArrayItem(psArray, i);
	    piArray[j] = psTemp->valueint;
	    psTemp = NULL;
	}
	psArray = NULL;
	return FUNC_OK;
    }

    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectDoubleArray
*
* Summary:
*        Get the double array
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        double* piArray -- Pointer that holds the double array(if pass NULL to pdArray,we can get the array size)
*        int* piSize -- Pointer that holds the array size
*
  * Parameter Output:
*	pdArray,piSize
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectDoubleArray(const cJSON* const psObject, const char* const pcKey, double* pdArray, int* piSize )
{
    cJSON *psArray = NULL;
    cJSON *psTemp = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }

    if(NULL == piSize)
    {
	return FUNC_FAILED;
    }
	
    if(NULL == pdArray)
    {
	if(FUNC_OK == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_OK;
	}
    }
    else
    {
	if(FUNC_FAILED == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_FAILED;
	}

	if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
	{
	    return FUNC_FAILED;
	}
	
	for (int i = 0,j = 0; i < *piSize && j < *piSize; ++i,++j)
	{
	    psTemp = cJSON_GetArrayItem(psArray, i);
	    pdArray[j] = psTemp->valuedouble;
	    psTemp = NULL;
	}
	psArray = NULL;
	return FUNC_OK;
    }
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectStringArray
*
* Summary:
*        Get the string array
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        char (*pcArray)[MAXSIZE] -- Pointer that holds the string array(if pass NULL to pcArray,we can get the array size)
*        int* piSize -- Pointer that holds the array size
*
* Parameter Output:
*	pcArray,piSize
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectStringArray(const cJSON* const psObject, const char* const pcKey, char (*pcArray)[MAXSIZE],int* piSize)
{
    cJSON* pscJSONStringArray = NULL;
    cJSON* pscJSONStringTemp = NULL;
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }

    if(NULL == piSize)
    {
	return FUNC_FAILED;
    }
    if(NULL == pcArray)
    {
	if(FUNC_OK == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_OK;
	}
    }
    else
    {
	if(FUNC_FAILED == LuxcJSONGetObjectArraySize(psObject, pcKey, piSize))
	{
	    return FUNC_FAILED;
	}

	if(NULL == (pscJSONStringArray = cJSON_GetObjectItem(psObject, pcKey)))
	{
	    return FUNC_FAILED;
	}
	
	for (int i = 0; i < *piSize; ++i)
	{
	    pscJSONStringTemp = cJSON_GetArrayItem(pscJSONStringArray, i);
	    LuxStrcpy(pcArray[i],pscJSONStringTemp->valuestring);
	}
	return FUNC_OK;
    }
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetArrayRowColumnSize
*
* Summary:
*        Get the two-dimensional array's row and column
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        int* piRow -- Pointer that holds the row size
*        int* piColumn -- Pointer that holds the column size
*
* Parameter Output:
*	piRow,piColumn
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetArrayRowColumnSize(const cJSON* const psObject, const char* const pcKey,int* piRow,int* piColumn)
{
    cJSON* psArray =NULL;
    cJSON *psArray21 = NULL;
    
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piRow || NULL == piColumn)
    {
	return FUNC_FAILED;
    }

    if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
    {
	return FUNC_FAILED;
    }
    *piRow = cJSON_GetArraySize(psArray);
    
    if(NULL == (psArray21 = cJSON_GetArrayItem(psArray, 0)))
    {
	return FUNC_FAILED;
    }
    *piColumn = cJSON_GetArraySize(psArray21);
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectIntArray2
*
* Summary:
*        Get the two-dimensional array
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        int (*piArray2)[MAXSIZE] -- Pointer that holds the two-dimensional arrray
*        int* piRow -- Pointer that holds the row size
*        int* piColumn -- Pointer that holds the column size
*
* Parameter Output:
*	piArray2,piRow,piColumn
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectIntArray2(const cJSON* const psObject, const char* const pcKey, int (*piArray2)[MAXSIZE],int* piRow, int* piColumn)
{
    cJSON *psArray = NULL;
    cJSON *psArrayTemp = NULL;
    cJSON *psValueTemp = NULL;
    
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piRow || NULL == piColumn)
    {
	return FUNC_FAILED;
    }
	
    if(NULL == piArray2)
    {
	if(FUNC_OK == LuxcJSONGetArrayRowColumnSize(psObject, pcKey, piRow, piColumn))
	{
	    return FUNC_OK;
	}
    }
    else
    {
	if(FUNC_FAILED == LuxcJSONGetArrayRowColumnSize(psObject, pcKey, piRow, piColumn))
	{
	    return FUNC_FAILED;
	}
   
	
	if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
	{
	    return FUNC_FAILED;
	}
  
	for (int i = 0; i < *piRow; ++i )
	{
	    psArrayTemp = cJSON_GetArrayItem(psArray, i);
	    for(int j = 0; j < *piColumn; ++j){
		psValueTemp = cJSON_GetArrayItem(psArrayTemp, j);
		piArray2[i][j] = psValueTemp->valueint;
		psValueTemp= NULL;
	    }
	    psArrayTemp = NULL;
	}
  
	return FUNC_OK;
    }
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONGetObjectDoubleArray2
*
* Summary:
*        Get the two-dimensional array
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 const cJSON* psObject -- The HEAD pointer of the CJSON entity
*        const char* const pcKey -- Key/Name
*        double (*piArray2)[MAXSIZE] -- Pointer that holds the two-dimensional arrray
*        int* piRow -- Pointer that holds the row size
*        int* piColumn -- Pointer that holds the column size
*
* Parameter Output:
*	pdArray2,piRow,piColumn
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONGetObjectDoubleArray2(const cJSON* const psObject, const char* const pcKey, double (*pdArray2)[MAXSIZE],int* piRow, int* piColumn)
{
    cJSON *psArray = NULL;
    cJSON *psArrayTemp = NULL;
    cJSON *PsValueTemp = NULL;
    
    if(NULL == psObject)
    {
	return FUNC_FAILED;
    }
    if(false == cJSON_HasObjectItem(psObject, pcKey))
    {
	return FUNC_FAILED;
    }
    if(NULL == piRow || NULL == piColumn)
    {
	return FUNC_FAILED;
    }
    if(NULL == pdArray2)
    {
	if(FUNC_OK == LuxcJSONGetArrayRowColumnSize(psObject, pcKey, piRow, piColumn))
	{
	    return FUNC_OK;
	}
    }
    else
    {
	if(FUNC_FAILED == LuxcJSONGetArrayRowColumnSize(psObject, pcKey, piRow, piColumn))
	{
	    return FUNC_FAILED;
	}
	
	if(NULL == (psArray = cJSON_GetObjectItem(psObject, pcKey)))
	{
	    return FUNC_FAILED;
	}
	for (int i = 0; i < *piRow; ++i )
	{
	    psArrayTemp = cJSON_GetArrayItem(psArray, i);
	    for(int j = 0; j < *piColumn; ++j)
	    {
		PsValueTemp = cJSON_GetArrayItem(psArrayTemp, j);
		pdArray2[i][j] = PsValueTemp->valuedouble;
		PsValueTemp = NULL;
	    }
	    psArrayTemp = NULL;
	}
	return FUNC_OK;
    }
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONDelete
*
* Summary:
*        Delete a cJSON entity and all subentities        
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 cJSON* psItem -- the HEAD pointer
*        
* Parameter Output:
*        None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONDelete(cJSON* psItem)
{
    if(NULL != psItem)
    {
	cJSON_Delete(psItem);
    }
    return FUNC_OK;
}

/***********************************************************
* Name:
*	 LuxcJSONFree
*
* Summary:
*        free object
*
* Return Value:
*	 EFuncRetCode(FUNC_FAILED or FUNC_OK)
*
* Parameter Input:
*	 cJSON* psItem -- the HEAD pointer
*        
* Parameter Output:
*        None
*
* Author:
*	Laurence.Zhou@luxshare-ict.com: Initial Version
*
***********************************************************/
EFuncRetCode LuxcJSONFree(void* psObject)
{
    if(NULL != psObject)
    {
	cJSON_free(psObject);
    }
    return FUNC_OK;
}






