#ifndef JSON_VC_WRAPPER_H
#define JSON_VC_WRAPPER_H

#include "_nlohmann_json_wrapper.h"
#include <atlstr.h> // for CString
#include <atltypes.h> // for CPoint, CSize, CRect

#include "StringHelper.h"

// wchar_t定义to_json没用，直接用j["keyname"] = utf16_8(wstr);
// GDCPP_API void to_json(jsonobj& j, const wchar_t * p);

// wstring定义to_json没用，直接用j["keyname"] = utf16_8(wstr);
// GDCPP_API void to_json(jsonobj& j, const std::wstring& p);

// std::wstring用from_josn会报错，用下面的toWstring
//GDCPP_API void from_json(const jsonobj& j, std::wstring& p);
bool  toWstring(const jsonobj& j, std::wstring& dst);

template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int  readWstring(const jsonobj& j, KeyT key, std::wstring& dst)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}

	if (it->is_string()) { // 判断是否为string类型的数据，避免get函数抛出异常
		dst = utf8_16(it->get<std::string>());
		return 1;
	}
	else {
		return -1;
	}
}

template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int  readWstringVector(const jsonobj& j, KeyT key, std::vector<std::wstring>& dst, bool clearbeforeread)
{
	if (clearbeforeread) {
		dst.clear();
	}
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	std::string str;
	for (auto& i : *it) {
		str = i.get<std::string>();
		dst.push_back(utf8_16(str));
	}
	return int(it->size());
}


template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int  readWstring(const jsonobj& j, KeyT key, std::wstring& dst, const std::wstring &def)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		dst = def;
		return 0;
	}

	if (it->is_string()) { // 判断是否为string类型的数据，避免get函数抛出异常
		dst = utf8_16(it->get<std::string>());
		return 1;
	}
	else {
		return -1;
	}
}

void to_json(jsonobj& j, const CString& p);
void from_json(const jsonobj& j, CString& p);

void to_json(jsonobj& j, const CPoint& p);
void from_json(const jsonobj& j, CPoint& p);

void to_json(jsonobj& j, const CSize& p);
void from_json(const jsonobj& j, CSize& p);

void to_json(jsonobj& j, const CRect& p);
void from_json(const jsonobj& j, CRect& p);


/**     @addtogroup Vector
 *      @brief std::vector <---> jsonobj
 *      @{*/
 /// \brief std::vector <T> -> json，T不要是指针类型，模板匹配有问题
 /// \details 注意会先清空j，如果j之前不是array也会强制变成array.
template <typename T>
void to_json(jsonobj& j, const std::vector <T>& p) {
    j = jsonobj::array(); //先清空
    int num = int(p.size());
    for (int i = 0; i < num; i++) {
        j.push_back(p.at(i));
    }
}

/// \brief json -> std::vector <T>，T不要是指针类型，模板匹配有问题
/// \details 注意会先清空p！不想清空就用\ref readVector
template <typename T>
void from_json(const jsonobj& j, std::vector <T>& p) {
    p.clear(); //先清空
    if (j.is_array()) {
        size_t num = j.size();
        for (size_t i = 0; i < num; i++) {
            p.push_back(j.at(i).get<T>());
        }
    }
}

/// \brief json --> std::vector<ValueT>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值，类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector(const jsonobj& j, KeyT key, std::vector<ValueT>& dst)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	int num = int(it->size());
	for (int i = 0; i < num; i++) {
		// 基础类不能用from_json，只能用get_to
		dst.push_back(it->at(i).template get<ValueT>());
	}
	return num;
}

template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector2D(const jsonobj& j, std::vector< std::vector<ValueT>>& dst)
{
	if (!j.is_array()) { //not array
		return -1;
	}
	int num = int(j.size());
	for (int i = 0; i < num; i++) {
		std::vector<ValueT> sub;
		readVector(j.at(i), sub);
		dst.push_back(sub);
	}
	return num;
}

template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector2D(const jsonobj& j, KeyT key, std::vector< std::vector<ValueT>>& dst)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	int num = int(it->size());
	for (int i = 0; i < num; i++) {
		std::vector<ValueT> sub;
		readVector(it->at(i), sub);
		dst.push_back(sub);
	}
	return num;
}



/// \brief json --> std::vector<ValueT>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename ValueT>
int readVector(const jsonobj& j, std::vector<ValueT>& dst)
{
	if (!j.is_array()) { //not array
		return -1;
	}
	int num = int(j.size());
	for (int i = 0; i < num; i++) {
		ValueT tmp;
		j.at(i).template get_to<ValueT>(tmp);
		dst.push_back(tmp);
	}
	return num;
}

/// \brief json --> std::vector<ValueT*>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值，类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readPtrVector(const jsonobj& j, KeyT key, std::vector<ValueT*>& dst)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	int num = int(it->size());
	for (int i = 0; i < num; i++) {
		auto* item = new ValueT();
		it->at(i).template get_to<ValueT>(*item);
		dst.push_back(item);
	}
	return num;
}

/// \brief json --> std::vector<ValueT*>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename ValueT>
int readPtrVector(const jsonobj& j, std::vector<ValueT*>& dst)
{
	if (!j.is_array()) { //not array
		return -1;
	}
	int num = int(j.size());
	for (int i = 0; i < num; i++) {
		auto* item = new ValueT();
		j.at(i).template get_to<ValueT>(*item);
		dst.push_back(item);
	}
	return num;
}

/// \brief std::vector<T> -> json
/// \details
template <typename T>
int writeVector(jsonobj& j, const std::vector<T>& p, bool clean=false) {
	if (clean) {//写入前强制清空
		j = jsonobj::array();
	}else if (!j.is_array()) {
		return -1;
	}
	int num = int(p.size());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, p.at(i));
		j.push_back(x);
	}
	return num;
}

/// \brief std::vector<T> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writeVector(jsonobj& j, KeyT key, const std::vector<T>& p, bool clean = false) {
	auto it = j.find(key);
	if (it == j.end() || it->is_null() || clean) {//没找到或强制清空
		j[key] = jsonobj::array(); //先清空
	}
	else if (!it->is_array()) {
		return -1;
	}
	int num = int(p.size());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, p.at(i));
		j[key].push_back(x);
	}
	return num;
}

/// \brief std::vector<T*> -> json
/// \details
template <typename T>
int writePtrVector(jsonobj& j, const std::vector<T*>& p, bool clean = false) {
	if (clean) {//写入前强制清空
		j = jsonobj::array();
	}
	else if (!j.is_array()) {
		return -1;
	}
	int num = int(p.size());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, *p.at(i));
		j.push_back(x);
	}
	return num;
}

/// \brief std::vector<T*> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writePtrVector(jsonobj& j, KeyT key, const std::vector<T*>& p, bool clean=false) {
	auto it = j.find(key);
	if (it == j.end() || it->is_null() || clean) {//没找到或强制清空
		j[key] = jsonobj::array(); //先清空
	}
	else if (!it->is_array()) {
		return -1;
	}
	int num = int(p.size());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, *p.at(i));
		j[key].push_back(x);
	}
	return num;
}

/// \brief json --> std::vector<std::shared_ptr<ValueT>>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值，类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readSharedPtrVector(const jsonobj& j, KeyT key, std::vector<std::shared_ptr<ValueT>>& dst)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	int num = int(it->size());
	for (int i = 0; i < num; i++) {
		auto item = std::shared_ptr<ValueT>::create();
		it->at(i).template get_to<ValueT>(*item);
		dst.append(item);
	}
	return num;
}

/// \brief json --> std::vector<std::shared_ptr<ValueT>>，不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配，需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0，找到但不是数组类型-1，有数据返回读到的数据类型。
template <typename ValueT>
int readSharedPtrVector(const jsonobj& j, std::vector<std::shared_ptr<ValueT>>& dst)
{
	if (!j.is_array()) { //not array
		return -1;
	}
	int num = int(j.size());
	for (int i = 0; i < num; i++) {
		auto item = std::shared_ptr<ValueT>::create();
		j.at(i).template get_to<ValueT>(*item);
		dst.append(item);
	}
	return num;
}

/// \brief std::vector<std::shared_ptr<T>> -> json
/// \details
template <typename T>
int writeSharedPtrVector(jsonobj& j, const std::vector<std::shared_ptr<T>>& p) {
	if (!j.is_array()) {
		return -1;
	}
	int num = int(p.count());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, *p.at(i));
		j.push_back(x);
	}
	return num;
}

/// \brief std::vector<std::shared_ptr<T>> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writeSharedPtrVector(jsonobj& j, KeyT key, const std::vector<std::shared_ptr<T>>& p) {
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		j[key] = jsonobj::array(); //先清空
	}
	else if (!it->is_array()) {
		return -1;
	}
	int num = int(p.count());
	for (int i = 0; i < num; i++) {
		jsonobj x;
		to_json(x, *p.at(i));
		j[key].push_back(x);
	}
	return num;
}

/**     @} vector*/


/**     @addtogroup Array
 *      @brief Array <---> jsonobj
  *     @{*/

/// \brief json --> 数组ValueT dst[maxnum]
/// 如果json中的数量超过maxnum，只读maxnum个，不报错。
/// \return 返回读到数据个数。<br>
/// 0表示没有找到key或数值为空，<br>
/// -1表示json[key]不是数组，<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readArray(const jsonobj &j, KeyT key, ValueT* dst, unsigned maxnum)
{
    auto it = j.find(key);
    if(it == j.end() || it->is_null()) {//没找到
        return 0;
    }
    if(!it->is_array()){ //not array
        return -1;
    }
    uint32_t num = uint32_t(it->size());
	uint32_t readnum = (num > maxnum) ? maxnum : num;

    for(uint32_t i=0; i< readnum; i++){
		it->at(i).template get_to<ValueT>(dst[i]);
    }
    return int(readnum);
}

/// \brief json --> 数组ValueT dst[maxnum]
/// 如果json中的数量超过maxnum，只读maxnum个，不报错。
/// \return 返回读到数据个数。<br>
/// 0表示没有找到key或数值为空，<br>
/// -1表示json[key]不是数组，<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readAnyArray(const jsonobj& j, KeyT key, ValueT* dst, unsigned maxnum)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	uint32_t num = uint32_t(it->size());
	uint32_t readnum = (num > maxnum) ? maxnum : num;

	for (uint32_t i = 0; i < readnum; i++) {
		from_json(it->at(i), dst[i]);
	}
	return int(readnum);

}

template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readWStringArray(const jsonobj& j, KeyT key, std::wstring* dst, unsigned maxnum)
{
	auto it = j.find(key);
	if (it == j.end() || it->is_null()) {//没找到
		return 0;
	}
	if (!it->is_array()) { //not array
		return -1;
	}
	uint32_t num = uint32_t(it->size());
	uint32_t readnum = (num > maxnum) ? maxnum : num;

	std::string str;
	for (uint32_t i = 0; i < readnum; i++) {
		it->at(i).get_to(str);
		dst[i] = utf8_16(str);
	}
	return int(readnum);

}

///获取json中名为key的数组长度，不存在或null返回0，不是数组返回-1，数组返回数组长度
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readArrayNum(const jsonobj &j, KeyT key)
{
    auto it = j.find(key);
    if(it == j.end() || it->is_null()) {//没找到
        return 0;
    }
    if(!it->is_array()){ //not array
        return -1;
    }
    return int(it->size());
}

/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int writeArray(jsonobj &j, KeyT key, const ValueT* src, size_t num)
{
	auto tmp = jsonobj::array();
	for (size_t i = 0; i < num; i++) {
		tmp.push_back(src[i]);
	}

	j[key] = tmp;

    return int(num);
}

/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int writeAnyArray(jsonobj& j, KeyT key, const ValueT* src, size_t num)
{
	auto tmp = jsonobj::array();
	jsonobj sub;
	for (size_t i = 0; i < num; i++) {
		to_json(sub, src[i]);
		tmp.push_back(sub);
	}

	j[key] = tmp;

	return int(num);
}

template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeWStringArray(jsonobj& j, KeyT key, const std::wstring* src, size_t num)
{
	j[key] = jsonobj::array();

	auto& it = j[key];
	std::string  str;
	for (size_t i = 0; i < num; i++) {
		str=utf16_8(src[i]);
		it.push_back(str);
	}

	return int(num);
}
/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeArray(jsonobj& j, KeyT key, const wchar_t ** src, size_t num)
{
    j[key] = jsonobj::array();

    auto& it = j[key];

    USES_CONVERSION;
    for (size_t i = 0; i < num; i++) {
        it.push_back(W2A(src[i]));
    }

    return int(num);
}

/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeArray(jsonobj& j, KeyT key, const char** src, size_t num)
{
    j[key] = jsonobj::array();

    auto& it = j[key];

    USES_CONVERSION;
    for (size_t i = 0; i < num; i++) {
        it.push_back(src[i]);
    }

    return int(num);
}


/**     @} Array*/



#endif // JSON_VC_WRAPPER_H
