#pragma once
#include <string>
#include <vector>
#include <map>
#include <memory>


#ifdef _EXPORTING
#define CLASS_DECLSPEC    __declspec(dllexport)
#else
#define CLASS_DECLSPEC    __declspec(dllimport)
#endif

CLASS_DECLSPEC std::string WideChartoUTF8(const std::wstring &str);
CLASS_DECLSPEC std::wstring UTF8toWideChar(const std::string &str);

#ifdef _EXPORTING
std::string URLencode(const std::string &orgstr);
std::string URLencode(const std::wstring &orgstr);
std::string CreateQueryURI(std::map<std::string, std::string> data, bool add = false);
std::string MakeCookie(std::multimap<std::string, std::string> setcookie);
std::vector<std::wstring> GetLocalDirFiles(std::wstring path);

std::string SystemStringToStdString(System::String^ str);
std::wstring SystemStringToStdWString(System::String^ str);
#endif

class jsonitem;

typedef std::shared_ptr<jsonitem> pjson;

extern pjson null_json;


class CLASS_DECLSPEC jsonitem
{
protected:
	virtual void parse(std::string str);
public:
	typedef enum { null, string, number, boolean, structure } itemtype;
	itemtype type;
	std::string json;

	static pjson Create(std::string str);

	virtual inline pjson operator[](std::string key){
		return null_json;
	}
	virtual inline pjson operator[](int index){
		return null_json;
	}
	virtual inline size_t size(){
		return 1;
	}
	inline bool GetBool() {
		if ((type == jsonitem::boolean) && (json == "true")) return true;
		return false;
	}
	virtual inline std::wstring GetString() {
		return L"";
	}
	virtual inline double GetDouble() {
		return 0;
	}
	virtual inline INT64 GetInteger() {
		return 0;
	}
};

class CLASS_DECLSPEC json_string : public jsonitem
{
private:
	std::wstring value;
protected:
	void parse(std::string str);
public:
	inline std::wstring GetString() {
		return value;
	}
};

class CLASS_DECLSPEC json_number : public jsonitem
{
private:
	double value;
protected:
	void parse(std::string str);
public:
	inline double GetDouble() {
		return value;
	}
	inline INT64 GetInteger() {
		INT64 result;
		std::stringstream out(json);
		out >> result;
		return result;
	}
};

class CLASS_DECLSPEC json_object : public jsonitem
{
private:
	std::map<std::string, pjson> members;
protected:
	void parse(std::string str);
public:
	inline pjson operator[](std::string key){
		auto p = members[key];
		return (p) ? p : null_json;
	}
	inline std::map<std::string, pjson>::iterator begin(){
		return members.begin();
	}
	inline std::map<std::string, pjson>::iterator end(){
		return members.end();
	}
	inline size_t size(){
		return members.size();
	}
};

class CLASS_DECLSPEC json_array : public jsonitem
{
private:
	std::vector<pjson> array;
protected:
	void parse(std::string str);
public:
	inline pjson operator[](int index){
		auto p = array[index];
		return (p) ? p : null_json;
	}
	inline size_t size(){
		return array.size();
	}
};

