// FileUtils.cpp: implementation of the CFileUtils class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FileUtils.h"
#include "Win32Error.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

DWORD CFileUtils::lastError_;

CFileUtils::CFileUtils()
{

}

CFileUtils::~CFileUtils()
{

}

bool CFileUtils::ReadFile(const cmString& fileName, string& fileContent)
{
	HANDLE hFile;
	DWORD size;
	DWORD read;
	char* buf;
	BOOL ret;

	hFile = ::CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return false;

	size = ::GetFileSize(hFile, NULL);

	buf = new char[size + 1];
	buf[size] = '\0';

	ret = ::ReadFile(hFile, buf, size, &read, NULL);
	if (ret && (size == read)) {
		fileContent = buf;
		ret = true;
	} else {
		fileContent = "";
		ret = false;
	}

	::CloseHandle(hFile);

	delete [] buf;
	
	return (ret == TRUE);
}

bool CFileUtils::WriteFile(const cmString& fileName, const string& fileContent)
{
	HANDLE hFile;
	DWORD written;
	BOOL ret;

	hFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		lastError_ = ::GetLastError();
		return false;
	}
	ret = ::WriteFile(hFile, fileContent.c_str(), fileContent.size(), &written, NULL);
	
	::CloseHandle(hFile);

	return (ret && (fileContent.size() == written));
}

bool CFileUtils::ReadBinaryFile(const cmString& fileName, vector<BYTE>& fileContent)
{
	HANDLE hFile;
	DWORD size;
	DWORD read;
	BYTE* buf;
	BOOL ret;

	fileContent.clear();
	hFile = ::CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return false;

	size = ::GetFileSize(hFile, NULL);

	buf = new BYTE[size];
	//buf[size] = '\0';

	ret = ::ReadFile(hFile, buf, size, &read, NULL);
	if (ret && (size == read)) {
		for (int i = 0; i < size; i++) 
			fileContent.push_back(buf[i]);
		ret = true;
	} else {
		ret = false;
	}

	::CloseHandle(hFile);

	delete [] buf;
	
	return (ret == TRUE);
}

bool CFileUtils::WriteBinaryFile(const cmString& fileName, const vector<BYTE>& fileContent)
{
	HANDLE hFile;
	DWORD written;
	BOOL ret;

	hFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		lastError_ = ::GetLastError();
		return false;
	}

	BYTE* buf;

	buf = new BYTE[fileContent.size()];
	for (int i = 0; i < fileContent.size(); i++)
		buf[i] = fileContent[i];

	ret = ::WriteFile(hFile, buf, fileContent.size(), &written, NULL);
	
	delete [] buf;

	::CloseHandle(hFile);

	return (ret && (fileContent.size() == written));
	
}

DWORD CFileUtils::GetLastError(cmString* errDescription)
{
	if (errDescription) {
		CWin32Error e(lastError_);

		*errDescription = e.Description();
	}

	return lastError_;	
}

set<cmString> CFileUtils::GetFileList(const cmString& pathName, const cmString& filter)
{
	CFileFind f;
	cmString tmp;
	set<cmString> list;
	BOOL ret;
	cmString fileName;

	tmp = pathName;
	if (tmp[tmp.GetLength() - 1] != _T('\\'))
		tmp += _T("\\");
	tmp += filter;

	ret = f.FindFile(tmp);
	while (ret) {
	
		ret = f.FindNextFile();

		if (!f.IsDirectory() && !f.IsDots()) {
			fileName = f.GetFileName();
			list.insert(fileName);
		}
	}

	return list;
}