#include "common.h"

CDropbox::CDropbox()
{
	PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE };
	pd.szName = MODULE;
	pd.type = PROTOTYPE_VIRTUAL;
	CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);

	HookEventObj(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown, this);
	HookEventObj(ME_SYSTEM_MODULESLOADED, OnModulesLoaded, this);
	HookEventObj(ME_DB_CONTACT_DELETED, OnContactDeleted, this);
	HookEventObj(ME_OPT_INITIALISE, OnOptionsInitialized, this);
	HookEventObj(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu, this);

	CreateProtoServiceFunction(MODULE, PS_GETCAPS, ProtoGetCaps);
	CreateProtoServiceFunctionObj(PSS_FILE, ProtoSendFile, this);
	CreateProtoServiceFunctionObj(PSS_MESSAGE, ProtoSendMessage, this);
	CreateProtoServiceFunctionObj(PSR_MESSAGE, ProtoReceiveMessage, this);

	InitializeIcons();
	InitializeMenus();

	commands["help"] = CDropbox::CommandHelp;
	commands["content"] = CDropbox::CommandContent;
	commands["share"] = CDropbox::CommandShare;
	commands["delete"] = CDropbox::CommandDelete;

	hFileProcess = hMessageProcess = 1;
	hDefaultContact = hTransferContact = 0;
}

MCONTACT CDropbox::GetDefaultContact()
{
	if (!hDefaultContact)
		hDefaultContact = db_find_first(MODULE);

	if (!hDefaultContact)
	{
		hDefaultContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0);
		if (!CallService(MS_PROTO_ADDTOCONTACT, hDefaultContact, (LPARAM)MODULE))
		{
			db_set_s(NULL, MODULE, "Nick", MODULE);
			db_set_s(hDefaultContact, MODULE, "Nick", MODULE);
			db_set_ws(hDefaultContact, "CList", "MyHandle", L"Dropbox");

			int status = db_get_w(hDefaultContact, MODULE, "Status", ID_STATUS_OFFLINE);
			if (HasAccessToken() && status == ID_STATUS_OFFLINE)
				db_set_w(hDefaultContact, MODULE, "Status", ID_STATUS_ONLINE);
		}
	}

	return hDefaultContact;
}

bool CDropbox::HasAccessToken()
{
	return db_get_sa(NULL, MODULE, "TokenSecret") != NULL;
}

void CDropbox::RequestAcceessToken()
{
	ShellExecuteA(NULL, "open", DROPBOX_WWW_URL DROPBOX_API_VER "/oauth2/authorize?response_type=code&client_id=" DROPBOX_API_KEY, NULL, NULL, SW_SHOWDEFAULT);

	char request_token[128] = { 0 };

	if (DialogBoxParam(
		g_hInstance,
		MAKEINTRESOURCE(IDD_TOKEN_REQUEST),
		NULL,
		CDropbox::TokenRequestProc,
		(LPARAM)&request_token) == IDOK)
	{
		char data[1024];
		mir_snprintf(
			data,
			SIZEOF(data),
			"grant_type=authorization_code&code=%s",
			request_token);

		HttpRequest *request = new HttpRequest(hNetlibUser, REQUEST_POST, DROPBOX_API_URL "/oauth2/token");
		request->pData = mir_strdup(data);
		request->dataLength = (int)strlen(data);
		request->AddHeader("Content-Type", "application/x-www-form-urlencoded");
		request->AddBasicAuthHeader(DROPBOX_API_KEY, DROPBOX_API_SECRET);

		mir_ptr<NETLIBHTTPREQUEST> response(request->Send());

		delete request;

		MCONTACT hContact = CDropbox::GetDefaultContact();

		if (response)
		{
			JSONNODE *root = json_parse(response->pData);
			if (root)
			{
				if (response->resultCode == HTTP_STATUS_OK)
				{
					JSONNODE *node = json_get(root, "access_token");
					ptrA access_token = ptrA(mir_u2a(json_as_string(node)));
					db_set_s(NULL, MODULE, "TokenSecret", access_token);

					if (hContact)
					{
						if (db_get_w(hContact, MODULE, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE)
							db_set_w(hContact, MODULE, "Status", ID_STATUS_ONLINE);
					}

					CDropbox::ShowNotification(TranslateT("You have been authorized"), MB_ICONINFORMATION);
				}
				else
				{
					JSONNODE *node = json_get(root, "error_description");
					ptrW error_description(json_as_string(node));

					CDropbox::ShowNotification((wchar_t*)error_description, MB_ICONERROR);
				}
			}
		}
		else
			HandleFileTransferError(response, hContact);
	}
}

void CDropbox::DestroyAcceessToken()
{
	HttpRequest *request = new HttpRequest(hNetlibUser, REQUEST_POST, DROPBOX_API_URL "/disable_access_token");
	mir_ptr<NETLIBHTTPREQUEST> response(request->Send());

	delete request;

	MCONTACT hContact = CDropbox::GetDefaultContact();

	db_unset(NULL, MODULE, "TokenSecret");
	if (hContact)
	{
		if (db_get_w(hContact, MODULE, "Status", ID_STATUS_ONLINE) == ID_STATUS_ONLINE)
			db_set_w(hContact, MODULE, "Status", ID_STATUS_OFFLINE);
	}
}

UINT CDropbox::RequestAcceessTokenAsync(void *owner, void* param)
{
	HWND hwndDlg = (HWND)param;
	CDropbox *instance = (CDropbox*)owner;

	EnableWindow(GetDlgItem(hwndDlg, IDC_AUTHORIZE), FALSE);
	SetDlgItemText(hwndDlg, IDC_AUTH_STATUS, TranslateT("in process..."));

	if (instance->HasAccessToken())
		instance->DestroyAcceessToken();

	char requestToken[128];
	GetDlgItemTextA(hwndDlg, IDC_REQUEST_CODE, requestToken, SIZEOF(requestToken));

	char data[1024];
	mir_snprintf(
		data,
		SIZEOF(data),
		"grant_type=authorization_code&code=%s",
		requestToken);

	HttpRequest *request = new HttpRequest(instance->hNetlibUser, REQUEST_POST, DROPBOX_API_URL "/oauth2/token");
	request->AddBasicAuthHeader(DROPBOX_API_KEY, DROPBOX_API_SECRET);
	request->AddHeader("Content-Type", "application/x-www-form-urlencoded");
	request->pData = mir_strdup(data);
	request->dataLength = (int)strlen(data);

	mir_ptr<NETLIBHTTPREQUEST> response(request->Send());

	delete request;

	MCONTACT hContact = instance->GetDefaultContact();

	if (response)
	{
		JSONNODE *root = json_parse(response->pData);
		if (root)
		{
			if (response->resultCode == HTTP_STATUS_OK)
			{
				JSONNODE *node = json_get(root, "access_token");
				ptrA access_token = ptrA(mir_u2a(json_as_string(node)));
				db_set_s(NULL, MODULE, "TokenSecret", access_token);

				if (hContact)
				{
					if (db_get_w(hContact, MODULE, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE)
						db_set_w(hContact, MODULE, "Status", ID_STATUS_ONLINE);
				}

				if (hwndDlg)
					SetDlgItemText(hwndDlg, IDC_AUTH_STATUS, TranslateT("you have been authorized"));
				else
					ShowNotification(TranslateT("you have been authorized"), MB_ICONINFORMATION);
			}
			else
			{
				JSONNODE *node = json_get(root, "error_description");
				ptrW error_description(json_as_string(node));

				if (hwndDlg)
					SetDlgItemText(hwndDlg, IDC_AUTH_STATUS, error_description);
				else
					ShowNotification((wchar_t*)error_description, MB_ICONERROR);
			}
		}
	}
	else
	{
		if (hwndDlg)
			SetDlgItemText(hwndDlg, IDC_AUTH_STATUS, TranslateT("unknown error"));
		else
		HandleFileTransferError(response, hContact);
	}

	SetDlgItemTextA(hwndDlg, IDC_REQUEST_CODE, "");

	return 0;
}