#ifndef _TOX_TRANSFERS_H_
#define _TOX_TRANSFERS_H_

struct FileTransferParam
{
	PROTOFILETRANSFERSTATUS pfts;
	FILE *hFile;
	uint32_t friendNumber;
	uint32_t fileNumber;
	uint64_t transferNumber;

	TOX_FILE_KIND transferType;

	FileTransferParam(uint32_t friendNumber, uint32_t fileNumber, const wchar_t *fileName, uint64_t fileSize)
	{
		hFile = nullptr;
		this->friendNumber = friendNumber;
		this->fileNumber = fileNumber;
		transferNumber = (((int64_t)friendNumber) << 32) | ((int64_t)fileNumber);

		pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
		pfts.flags = PFTS_UNICODE;
		pfts.hContact = NULL;
		pfts.totalFiles = 1;
		pfts.ptszFiles = (wchar_t**)mir_alloc(sizeof(wchar_t*)*(pfts.totalFiles + 1));
		pfts.ptszFiles[0] = pfts.tszCurrentFile = mir_wstrdup(fileName);
		pfts.ptszFiles[pfts.totalFiles] = nullptr;
		pfts.totalBytes = pfts.currentFileSize = fileSize;
		pfts.totalProgress = pfts.currentFileProgress = 0;
		pfts.currentFileNumber = 0;
		pfts.currentFileTime = now();
		pfts.tszWorkingDir = nullptr;

		transferType = TOX_FILE_KIND_DATA;
	}

	~FileTransferParam()
	{
		if (pfts.tszWorkingDir)
			mir_free(pfts.tszWorkingDir);
		mir_free(pfts.pszFiles[0]);
		mir_free(pfts.pszFiles);
		if (hFile) {
			fclose(hFile);
			hFile = nullptr;
		}
	}

	bool Resume()
	{
		if (hFile)
			return true;
		hFile = _wfopen(pfts.tszCurrentFile, L"wb+");
		if (hFile)
			_chsize_s(_fileno(hFile), pfts.currentFileSize);
		return hFile != nullptr;
	}

	void Pause()
	{
		if (hFile) {
			fclose(hFile);
			hFile = nullptr;
		}
	}

	void ChangeName(const wchar_t *fileName)
	{
		pfts.ptszFiles[0] = replaceStrW(pfts.tszCurrentFile, fileName);
	}

	uint8_t GetDirection() const
	{
		return (pfts.flags & PFTS_SENDING) ? 0 : 1;
	}
};

struct AvatarTransferParam : public FileTransferParam
{
	uint8_t hash[TOX_HASH_LENGTH];

	AvatarTransferParam(uint32_t friendNumber, uint32_t fileNumber, const wchar_t *fileName, uint64_t fileSize)
		: FileTransferParam(friendNumber, fileNumber, fileName, fileSize)
	{
		transferType = TOX_FILE_KIND_AVATAR;
	}
};

class CTransferList
{
private:
	std::map<int64_t, FileTransferParam*> transfers;

public:
	size_t Count() const
	{
		return transfers.size();
	}

	void Add(FileTransferParam *transfer)
	{
		if (transfers.find(transfer->transferNumber) == transfers.end())
			transfers[transfer->transferNumber] = transfer;
	}

	FileTransferParam* Get(uint32_t friendNumber, uint32_t fileNumber)
	{
		int64_t transferNumber = (((int64_t)friendNumber) << 32) | ((int64_t)fileNumber);
		if (transfers.find(transferNumber) != transfers.end())
			return transfers.at(transferNumber);
		return nullptr;
	}

	FileTransferParam* GetAt(size_t index)
	{
		if (index < Count()) {
			auto it = transfers.begin();
			std::advance(it, index);
			return it->second;
		}
		return nullptr;
	}

	void Remove(FileTransferParam *transfer)
	{
		if (transfer == nullptr)
			return;
		if (transfers.erase(transfer->transferNumber))
			delete transfer;
	}
};

#endif //_TOX_TRANSFERS_H_