/** @file asyncopfilehandler.cpp
 *  Implementation for the AsyncOpFileHandler class
 * 	@headerfile asyncopfilehandler.h "ux_core/asyncopfilehandler.h"
 *	@author Chris Burns (cburns@ea.com)
 *
 *	Core Technology UI
 *	(c) 2012 Electronic Arts Inc. 
 */

#include "EABaseTypesAsyncOp/asyncopfilehandler.h"

#include "EABaseTypesPlus/path.h"
#include "EABaseTypesPlus/vrefcountedica.h"

#include "EABaseTypes/string.h"
#include "EABaseTypes/factory.h"

#include "rw/core/filesys/async.h"

#include "coreallocator/icoreallocatormacros.h"

#include "eaassert/eaassert.h"

namespace EA
{
namespace Types
{

	/*! @class	AsyncOpFileResource
	*	@brief	Implementation of IFileResource for rwfilesystem AsyncOps
	*	Trivial, backed by a raw memory buffer
	*/
	class AsyncOpFileResource : public EA::Types::VRefCountedICA<EA::Types::IFileResource>
	{
	public:

		AsyncOpFileResource(EA::Allocator::ICoreAllocator* allocator, void* buffer, unsigned int size):
			EA::Types::VRefCountedICA<EA::Types::IFileResource>(allocator),
			mBuffer(buffer),
			mSize(size)
		{
		}

		virtual ~AsyncOpFileResource()
		{
			CORE_FREE(mAllocator, mBuffer);
			mBuffer = NULL;
		}

		virtual void* GetData()
		{
			return mBuffer;
		}

		virtual unsigned int GetSize() const
		{
			return mSize;
		}

	private:

		void*							mBuffer;
		unsigned int					mSize;
	};

	AsyncOpFileHandler::AsyncOpFileHandler( EA::Allocator::ICoreAllocator* allocator, const char* root)
		: EA::Types::AsyncFileHandler(allocator, root)
	{

	}

	/* virtual */ bool AsyncOpFileHandler::Exists(EA::Allocator::ICoreAllocator* allocator, const char* fileName)
	{
		EA::RawString path(allocator);
		EA::Types::Path::AppendRaw(path, mRoot, fileName);

		return rw::core::filesys::Exists(path.c_str());
	}

	//lint -efunc(904, UX::AsyncOpFileHandler::Load)
	/* virtual */ EA::Types::IFileResourceReturn AsyncOpFileHandler::Load(EA::Allocator::ICoreAllocator* allocator, const char* fileName)
	{
		void* buffer = NULL;
		unsigned int size = 0;

		rw::core::filesys::AsyncOp op;

		EA::RawString path(allocator);
		EA::Types::Path::AppendRaw(path, mRoot, fileName);

		// Open the file...
		op.Open(path.c_str(), rw::core::filesys::AsyncOp::FOPEN_READONLY);
		op.Wait();
		rw::core::filesys::Handle *handle = op.GetResultHandle();

		if(handle != NULL)
		{
			// file opened successfully

			// find out file size and alloc buffer
			size = static_cast<unsigned int>(rw::core::filesys::GetSize(handle));
			if(size == 0)
			{
				op.Close(handle);
				op.GetStatus(EA::Thread::kTimeoutNone);
				
				EA_FAIL_FORMATTED(("Filesize is 0 for file '%s'", fileName));

				return NULL;
			}

			// alloc the buffer for the file
			buffer = allocator->Alloc(size, "AsyncOpFileHandler Temp File Buffer", EA::Allocator::MEM_TEMP);

			// Read in whole file...
			op.Read(handle, buffer, static_cast<uint64_t>(0), static_cast<uint64_t>(size), NULL, NULL, 5);
			op.Wait();

			// find out how many bytes were read
			op.GetStatus(EA::Thread::kTimeoutNone);

			EA_ASSERT_FORMATTED(op.GetResultSize() == size, ("Read %d bytes when expecting %d bytes", op.GetResultSize(), size));

			// close file
			op.Close(handle);
			op.Wait();

			return CORE_NEW(allocator, "AsyncOpFileResource", EA::Allocator::MEM_TEMP) AsyncOpFileResource(allocator, buffer, size);
		}
		else
		{
			// the file could not be opened, return NULL
			return NULL;
		}
	}

}
}
