#pragma once
#include "stdafx.h"
#include <typeinfo>

#using "WebWindow.dll"

using namespace System;
using namespace WebWindow;

namespace BitcasaDLL {

	ref class jsonitemWrapper;

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

	public delegate void filetrans(Int64 transbyte);

	public ref class BitcasaWrapper
	{
	private:
		BitcasaAPI *obj;
	public:
		property System::String^ access_token{
			System::String^ get(){
				return gcnew System::String(obj->access_token.c_str());
			}
		}

		BitcasaWrapper();
		~BitcasaWrapper();

		bool prepare();

		////////////////////////////////////////
		int authenticate();
		int Grant_token(std::string auth_code){
			return obj->Grant_token(auth_code);
		}
		///////////////////////////////////////
		jsonitemWrapper^ ListFolder(System::String^ encoded_path);
		jsonitemWrapper^ ListFolder(System::String^ encoded_path, bool deep);
		bool AddFolder(System::String^ encoded_path, System::String^ newfoldername);
		bool DeleteFolder(System::String^ encoded_path);
		bool RenameFolder(System::String^ encoded_path_old, System::String^ newfoldername);
		bool CopyFolder(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfoldername);
		bool MoveFolder(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfoldername);
		//////////////////////////////////////
		bool UploadFile(System::String^ encoded_path, System::String^ infilename);
		bool UploadFile(System::String^ encoded_path, System::String^ infilename, filetrans^ callback);
		bool DownloadFile(System::String^ encoded_file_id, System::String^ filename, Int64 filesize);
		bool DownloadFile(System::String^ encoded_file_id, System::String^ filename, Int64 filesize, filetrans^ callback);
		bool _DeleteFile(System::String^ encoded_path);
		bool RenameFile(System::String^ encoded_path_old, System::String^ newfoldername);
		bool CopyFile(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfilename);
		bool MoveFile(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfilename);

	};

	public ref class ListLocalBitcasa
	{
	public:
		System::String^ name;
		Int64 size;
		DateTime CreationTime;
		DateTime LastWriteTime;

		static System::Collections::Generic::List<ListLocalBitcasa^>^ ListDir(System::String^ rootdir);
	};

	public ref class jsonitemWrapper
	{
	public:
		jsonitem::itemtype type;
		System::String^ json;

		static jsonitemWrapper^ Create(pjson item);

		virtual property jsonitemWrapper^ default [System::String^]{
			jsonitemWrapper^ get(System::String^){
				return jsonitemWrapper::Create(null_json);
			}
		}
		virtual inline jsonitemWrapper^ Items(size_t){
			return jsonitemWrapper::Create(null_json);
		}
		virtual property size_t size{
			size_t get(){
				return 1;
			}
		}
		inline bool GetBool() {
			if ((type == jsonitem::boolean) && (String::Compare(json, "true") == 0)) return true;
			return false;
		}
		virtual inline System::String^ GetString() {
			return L"";
		}
		virtual inline double GetDouble() {
			return 0;
		}
		virtual inline INT64 GetInteger() {
			return 0;
		}
	};

	public ref class json_stringWrapper : jsonitemWrapper
	{
	private:
		System::String^ value;
	public:
		void SetValue(std::wstring strvalue){
			value = gcnew System::String(strvalue.c_str());
		}
		inline System::String^ GetString() override {
			return value;
		}
	};

	public ref class json_numberWrapper : jsonitemWrapper
	{
	public:
		double value;
		inline double GetDouble() override{
			return value;
		}
		inline INT64 GetInteger() override{
			return Convert::ToInt64(json);
		}
	};

	public ref class json_objectWrapper : jsonitemWrapper
	{
	private:
		System::Collections::Hashtable members;
	public:
		void SetMembers(jsonitem* org){
			json_object* obj = static_cast<json_object*>(org);
			for (auto it = obj->begin(); it != obj->end(); ++it){
				members.Add(gcnew System::String(it->first.c_str()), jsonitemWrapper::Create(it->second));
			}
		}
		virtual property jsonitemWrapper^ default [System::String^]{
			jsonitemWrapper^ get(System::String^ key) override {
				auto p = members[key];
				return (p) ? (jsonitemWrapper^)p : jsonitemWrapper::Create(null_json);
			}
		}
		virtual property size_t size{
			size_t get() override{
				return members.Count;
			}
		}
	};

	public ref class json_arrayWrapper : jsonitemWrapper
	{
	private:
		System::Collections::Generic::List<jsonitemWrapper^> array;
	public:
		void SetArray(jsonitem* org){
			json_array *obj = dynamic_cast<json_array*>(org);
			if (!obj) return;
			for (size_t i = 0; i < obj->size(); i++){
				array.Add(jsonitemWrapper::Create((*obj)[i]));
			}
		}
		virtual inline jsonitemWrapper^ Items(size_t index) override{
			auto p = array[index];
			return (p) ? p : jsonitemWrapper::Create(null_json);
		}
		virtual property size_t size{
			size_t get() override{
				return array.Count;
			}
		}
	};

}