////////////////////////////////////////////////////////////////////////////////
// GameZArchive.h
// Parser for MW3 gamez.zbd files
// Copyright Bjoern Ganster
// Developed since 2022
////////////////////////////////////////////////////////////////////////////////

#ifndef GameZArchive__h
#define GameZArchive__h

#include "BGBase.h"
#include "Archive.h"
#include "XMLTree.h"

#include <set>

////////////////////////////////////////////////////////////////////////////////
// Implementation of an archive class for gamez.zbd files

struct MW3GameZHeader {
	uint32_t signature;
	uint32_t version;
	uint32_t textureCount;
	uint32_t textureOffset;
	uint32_t materialsOffset;
	uint32_t meshesOffset;
	uint32_t nodeArraySize;
	uint32_t nodeCount;
	uint32_t nodesOffset;
};

struct MW3PMGameZHeader {
	uint32_t signature;
	uint32_t version;
	uint32_t unknown;
	uint32_t textureCount;
	uint32_t textureOffset;
	uint32_t materialsOffset;
	uint32_t meshesOffset;
	uint32_t nodeArraySize;
	uint32_t nodeCount;
	uint32_t nodesOffset;
};

// GameZ reader for both MW3 and MW3:PM
// todo: create a common base class for MW3 and MW3:PM where decodeGameZMesh and decodeGameZPMMesh are distinguished by appropriate virtual method calls
class MW3GameZArchive : public MWArchive {
public:
	// Constructor
	MW3GameZArchive();

	// Destructor
	~MW3GameZArchive() OVERRIDE;

	// Open file
	bool open(const PathChar* PRJFN, bool readOnly = true) OVERRIDE;

	// Close file
	void close() OVERRIDE;

	// Read bufSize bytes from file numbered index at offset into buf
	bool getFileChunk(size_t index, size_t offset, void* buf, size_t bufSize) OVERRIDE;

	// Enter subdirectory
	bool enterSubDir(size_t /*index*/) OVERRIDE;

	bool enterSubDir(const char* /*dirName*/) OVERRIDE;

	// Leave subdirectory
	bool leaveDir() OVERRIDE;

	// Check if currently in sub directory
	bool inSubDir() const OVERRIDE;

	// Replace file
	bool replaceFile(size_t /*fileNum*/, const PathChar* /*srcFN*/) OVERRIDE;

	// Check if archive type supports file replacement
	bool replaceFilePossible() const OVERRIDE;

	// Check if entry index is a directory
	bool isDirectory(size_t /*index*/) const OVERRIDE;

	// Add files to archive
	void addFileToArchive(const PathChar* /*FN*/) OVERRIDE;
	bool canAddFilesToArchive() const OVERRIDE;

	// Decode a mesh stored in a MW3 gamez.zbd to something MechVM understands ...
	bool decodeGameZMesh(size_t fileNo, Mesh* mesh);
	bool decodeGameZPMMesh(size_t fileNo, Mesh* mesh);

	// Import a scene graph from a gamez.zbd
	void importGameZNodes(size_t fileNo);
	void importPMGameZNodes(size_t fileNo);

	// True if the file belongs to MW3:PM, false for MW3
	bool isPiratesMoonFile() const;

private:
	// Keep gamez.zbd in memory for fast access
	MemoryBlock mMb;

	// Pointer to the file header ...
	MW3GameZHeader* mMW3GameZHeader; // for MW3, null otherwise
	MW3PMGameZHeader* mMW3PMGameZHeader; // for MW3:PM, null otherwise

	// Keep track of which nodes were encountered as child nodes
	std::set<size_t> mChildNodeOffsets;

	// Import a scene graph from a gamez.zbd
	void importGameZNodesRec(size_t offset, XMLTreeIterator& iter, int recursionLevel);
	void importPMGameZNodesRec(size_t offset, XMLTreeIterator& iter, int recursionLevel);
};

#endif
