//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: standardFileLoader.inl
//      Краткое описание: загрузчик файлов из директории
//

namespace ker
{
	inline StandardFileLoader::StandardFileLoader(const std::string& dir)
	{
		this->dir = dir;
#ifdef _NOTFINAL
		data_struct* ds = new data_struct;
		ds->dh = dir;
		ds->fn.reset(&filenames);
		directory_viewer.reset(new Thread(&StandardFileLoader::readDirChangeThread, ds, true));
		if(!directory_viewer->getThreadHandle())
			lwar << "Cannot create thread for directory viewing";
		directory_viewer->setThreadPriority(BELOW_NORMAL_PRIORITY);
		directory_viewer->resume();
#endif
	};

	inline StandardFileLoader::~StandardFileLoader()
	{
		
		filenames.clear();
	};

	inline bool StandardFileLoader::open(const std::string& filename, FileData* data)
	{
		HANDLE file = CreateFile((dir + filename).c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
			OPEN_EXISTING, 0, NULL);
		if(file == INVALID_HANDLE_VALUE)
			return false;
		data->filename = filename;
		data->id = file;
		data->size = GetFileSize(file, NULL);
		data->full_path = dir + filename;
		data->path = dir;
		BY_HANDLE_FILE_INFORMATION info;
		GetFileInformationByHandle(file, &info);
		data->last_write_time.reset(new SystemTime(info.ftLastWriteTime));
		return true;
	};

	inline bool StandardFileLoader::close(const DFHANDLE id) const
	{
		if(!CloseHandle((HANDLE)id))
		{
			lwar << "Cannot close handle or invalid handle";
			return false;
		};
		return true;
	};

	inline bool StandardFileLoader::read(const DFHANDLE id, const unsigned int size, void* data) const
	{
		DWORD numOfbytesRead;
		if(!ReadFile((HANDLE)id, data, size, &numOfbytesRead, NULL))
		{
			lwar << "Cannot read from file";
			return false;
		};
		return true;
	};

	inline bool StandardFileLoader::skip(const DFHANDLE id, const unsigned int size) const
	{
		if(!SetFilePointer((HANDLE)id, size, NULL, FILE_CURRENT))
			return false;
		return true;
	};

	inline DWORD WINAPI StandardFileLoader::readDirChangeThread(LPVOID param)
	{
		data_struct* ds = (data_struct*)param;
		HANDLE dir_handle = CreateFile(ds->dh.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
			NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
		if(dir_handle == INVALID_HANDLE_VALUE)
		{
			lwar << "Cannot open directory: " << ds->dh << " in this directory cannot observe to changes";
			return 0;
		}
		FILE_NOTIFY_INFORMATION notify_info[notify_information_struct_num];
		DWORD struct_read;
		while(true)
		{
			BOOL res = ReadDirectoryChangesW(dir_handle, notify_info, 
				sizeof(FILE_NOTIFY_INFORMATION)*notify_information_struct_num,
				TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE, &struct_read, NULL, NULL);
			if(!res)
			{
				lwar << "ReadDirectoryChangesW error";
				continue;
			};
			CriticalSection section;
			section.enter();
			FILE_NOTIFY_INFORMATION* info = notify_info;
			do 
			{
				char filename[100];
				WideCharToMultiByte(CP_ACP, 0, info->FileName, info->FileNameLength/2, 
					filename, info->FileNameLength/2 + 1, 0, 0);
				filename[info->FileNameLength/2] = '\0';
				std::string str(filename);
				ds->fn->insert(str);
				info += info->NextEntryOffset;
			} 
			while(info->NextEntryOffset);
			FileManager::ptr()->sendSetOfChanges(*ds->fn);
			ds->fn->clear();
			section.leave();
		};
		CloseHandle(dir_handle);
		return 0;
	};

	inline const std::set<std::string>& StandardFileLoader::getSetOfChanges() const
	{
		return filenames;
	};
};
		