#pragma once

#include "CryHeaders.h"
#include "smartptr.h"

//////////////////////////////////////////////////////////////////////////
// Chunk file writer.
// Writes a chunk file sequentally. The chunks must be prepared before
// passing it to the object, because the data is written directly to the
// file and cannot be modified after writing.
// Error handling is performed through exceptions. This object is
// designed for complex write hierarchy, not for reusability of one robust
// instance.
// THROWS:
//  Error - generic exceptions
//  --std::ios::failure - IO failure
//////////////////////////////////////////////////////////////////////////
class CChunkFileWriter
{
public:
	typedef FILE_HEADER FileHeader;
	typedef CHUNK_HEADER ChunkHeader;

	// the exception class that methods of this class throw
	class Error
	{
	public:
		// constructs an error (exception) object out of a printf-like string
		Error (const char* szMessage, ...);
		// returns the error reason, in C string format
		const char* c_str() const;
	protected:
		std::string m_sMessage;
	};

	// Opens the given file and prepares it for writing chunk data
	CChunkFileWriter (const char* szFileName, int nFileType, int nVersion);
	~CChunkFileWriter (void);

	// writes the file header at the beginning of the file, given the current position
	// of the file and then returns to the current position
	void writeFileHeader ();

	// writes some fixed-length structure into the file
	template <typename T>
	void write(const T&x)
	{
		write (&x, sizeof(x));
	}

	// writes an array of the given type into the stream
	template <typename T>
	void writeArray (const T* arrData, unsigned numElements)
	{
		write (arrData, sizeof(T)*numElements);
	}

	// writes the array in the form of STL vector
	template <typename T>
	void writeVector(const std::vector<T>& arrData)
	{
		writeArray (&arrData[0], arrData.size());
	}

	// writes the given number of bytes into the file
	void write (const void* pData, unsigned int nDataSize);

	// returns the number of chunk headers present
	unsigned numChunks ()const;
	
	// returns the reference to the chunk by index.
	// the position is correctly set up in that chunk
	// it's acceptable to modify it, except the field with position
	ChunkHeader& getChunk(int nChunkIdx);

	// returns the chunk currently being written to;
	// the position is correctly set up in that chunk
	ChunkHeader& getChunk();

	// adds a new chunk to the sequence (thus closing the previous)
	// the FileOffset in the chunk header structure is ignored
	void addChunk (const ChunkHeader& chunk);

	// adds a new chunk to the sequence (thus closing the previous)
	void addChunk (ChunkTypes	nType, int nVersion, int nID);

	// returns the current position in the file, in bytes, from the beginning of the file
	int getFilePos ();
protected:

	// sets the file position
	void setFilePos(int nNewPos);

protected:
	// the file to which to write
	FILE* m_fStream;

	// the file header
	FileHeader m_FileHeader;

	// the chunk table
	typedef std::vector<ChunkHeader> ChunkHeaderArray;
	ChunkHeaderArray m_arrChunks;
};

// this is the reference target version of the CChunkFileWriter class.
// it's capable of reference counting and there's a smart pointer to it
class CChunkFileWriterRefTgt:
	public CChunkFileWriter,
	public _reference_target_t
{
public:
	CChunkFileWriterRefTgt (const char* szFileName, int nFileType, int nVersion):
		CChunkFileWriter (szFileName, nFileType, nVersion)
		{
		}
};

TYPEDEF_AUTOPTR(CChunkFileWriterRefTgt);
// to imitate that the original CChunkFileWriter is a reference target, redefine the autopointer