#include "stdafx.h"
#include "BitcasaWrapper.h"

using namespace BitcasaDLL;

std::string BitcasaDLL::SystemStringToStdString(System::String^ str){
	using namespace Runtime::InteropServices;
	const char* chars =
		(const char*)(Marshal::StringToHGlobalAnsi(str)).ToPointer();
	std::string result = chars;
	Marshal::FreeHGlobal(IntPtr((void*)chars));
	return result;
}

std::wstring BitcasaDLL::SystemStringToStdWString(System::String^ str){
	using namespace Runtime::InteropServices;
	const wchar_t* chars =
		(const wchar_t*)(Marshal::StringToHGlobalUni(str)).ToPointer();
	std::wstring result = chars;
	Marshal::FreeHGlobal(IntPtr((void*)chars));
	return result;
}

jsonitemWrapper^ jsonitemWrapper::Create(pjson item)
{
	jsonitemWrapper^ selfitem;
	if (!item) return gcnew jsonitemWrapper;
	switch (item->type){
	case jsonitem::null:
		selfitem = gcnew jsonitemWrapper;
		break;
	case jsonitem::string:
		selfitem = gcnew json_stringWrapper;
		dynamic_cast<json_stringWrapper^>(selfitem)->SetValue(item->GetString());
		break;
	case jsonitem::number:
		selfitem = gcnew json_numberWrapper;
		dynamic_cast<json_numberWrapper^>(selfitem)->value = (item->GetDouble());
		break;
	case jsonitem::boolean:
		selfitem = gcnew jsonitemWrapper;
		break;
	case jsonitem::structure:
		if (typeid(*item) == typeid(json_object)){
			selfitem = gcnew json_objectWrapper;
			dynamic_cast<json_objectWrapper^>(selfitem)->SetMembers(&*item);
		}
		else {
			selfitem = gcnew json_arrayWrapper;
			dynamic_cast<json_arrayWrapper^>(selfitem)->SetArray(&*item);
		}
		break;
	default:
		return gcnew jsonitemWrapper;
	}
	selfitem->type = item->type;
	selfitem->json = gcnew System::String(item->json.c_str());
	return selfitem;
}

BitcasaWrapper::BitcasaWrapper()
{
	obj = new BitcasaAPI;
}

BitcasaWrapper::~BitcasaWrapper()
{
	delete obj;
}


//Authentication
//	Login
int BitcasaWrapper::authenticate()
{
	LoginBitcasa login;
	System::String^ authorization_code = login.Login();

	if (String::IsNullOrEmpty(authorization_code)) return 1;

	std::string authcode = SystemStringToStdString(authorization_code);

	if (authcode.empty()) return 2;

	return obj->Grant_token(authcode);
}

bool BitcasaWrapper::prepare()
{
	if (!obj->access_token.empty()) {
		auto root = obj->ListFolder("/");
		if (root && (*root)["error"]->type == jsonitem::null) return true;
	}
	if (authenticate() == 0) return true;
	return false;
}


jsonitemWrapper^ BitcasaWrapper::ListFolder(System::String^ encoded_path)
{
	return jsonitemWrapper::Create(obj->ListFolder(SystemStringToStdString(encoded_path)));
}

jsonitemWrapper^ BitcasaWrapper::ListFolder(System::String^ encoded_path, bool deep)
{
	return jsonitemWrapper::Create(obj->ListFolder(SystemStringToStdString(encoded_path), deep));
}

bool BitcasaWrapper::AddFolder(System::String^ encoded_path, System::String^ newfoldername)
{
	return obj->AddFolder(SystemStringToStdString(encoded_path), SystemStringToStdWString(newfoldername));
}

bool BitcasaWrapper::DeleteFolder(System::String^ encoded_path)
{
	return obj->DeleteFolder(SystemStringToStdString(encoded_path));
}

bool BitcasaWrapper::RenameFolder(System::String^ encoded_path_old, System::String^ newfoldername)
{
	return obj->RenameFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdWString(newfoldername));
}

bool BitcasaWrapper::CopyFolder(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfoldername)
{
	return obj->CopyMoveFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdString(encoded_path_new), SystemStringToStdWString(newfoldername),BitcasaAPI::copy);
}
bool BitcasaWrapper::MoveFolder(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfoldername)
{
	return obj->CopyMoveFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdString(encoded_path_new), SystemStringToStdWString(newfoldername), BitcasaAPI::move);
}


bool BitcasaWrapper::UploadFile(System::String^ encoded_path, System::String^ infilename)
{
	return obj->UploadFile(SystemStringToStdString(encoded_path), SystemStringToStdWString(infilename));
}
bool BitcasaWrapper::UploadFile(System::String^ encoded_path, System::String^ infilename, filetrans^ callback)
{
	IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callback);
	return obj->UploadFile(SystemStringToStdString(encoded_path), SystemStringToStdWString(infilename), (void(*)(INT64))delegatePointer.ToPointer());
}

bool BitcasaWrapper::DownloadFile(System::String^ encoded_file_id, System::String^ filename, Int64 filesize)
{
	return obj->DownloadFile(SystemStringToStdString(encoded_file_id), SystemStringToStdWString(filename), filesize);
}
bool BitcasaWrapper::DownloadFile(System::String^ encoded_file_id, System::String^ filename, Int64 filesize, filetrans^ callback)
{
	IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callback);
	return obj->DownloadFile(SystemStringToStdString(encoded_file_id), SystemStringToStdWString(filename), filesize, (void(*)(INT64))delegatePointer.ToPointer());
}

bool BitcasaWrapper::_DeleteFile(System::String^ encoded_path)
{
	return obj->_DeleteFile(SystemStringToStdString(encoded_path));
}

bool BitcasaWrapper::RenameFile(System::String^ encoded_path_old, System::String^ newfoldername)
{
	return obj->RenameFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdWString(newfoldername));
}

bool BitcasaWrapper::CopyFile(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfilename)
{
	return obj->CopyMoveFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdString(encoded_path_new), SystemStringToStdWString(newfilename), BitcasaAPI::copy);
}
bool BitcasaWrapper::MoveFile(System::String^ encoded_path_old, System::String^ encoded_path_new, System::String^ newfilename)
{
	return obj->CopyMoveFolder(SystemStringToStdString(encoded_path_old), SystemStringToStdString(encoded_path_new), SystemStringToStdWString(newfilename), BitcasaAPI::move);
}
