////////////////////////////////////////////////////////////////////////////////
// Archive.h
// Abstract base class for MechWarrior archive files
// Copyright Bjoern Ganster
// Developed since 2008
////////////////////////////////////////////////////////////////////////////////

#ifndef Archive__h
#define Archive__h

#include "BGBase.h"
#include "BGCPString.h"
#include "MWBase.h"
#include "MemoryBlock.h"

#include <vector>

////////////////////////////////////////////////////////////////////////////////
// Abstract base class for MechWarrior archive files
// Currently implemented by MechWarriorIIPRJ

struct ArchiveEntry {
	size_t fileSize;
	size_t fileOffset;
	BGCPString filename;
	FileType fileType;
	size_t packedSize;
};

class MWArchive : public VirtualClass {
public:
	// Constructor
	MWArchive(const char* className, int ID = MWArchiveID);

	// Destructor
	~MWArchive() OVERRIDE;

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

	// Close file
	virtual void close() = 0;

	// Get number of entries in directory
	size_t getEntryCount() const;

	// Get name of entry
	virtual bool getEntryName(size_t index, BGCPString& name);

	// Get size of entry, 0: directory or error
	virtual size_t getFileSize(size_t index);

	// Get offset of file start inside prj file
	virtual size_t getFileOffset(size_t index);

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

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

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

	// Leave subdirectory
	virtual bool leaveDir();

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

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

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

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

	// Create a list of files
	void createFileList(const PathChar* FN);

	// Export all files in a mw2.prj file
	void exportToDirectory(const PathChar* saveFN);

	// Return index of file in current directory, or entryCount+1 if not found
	size_t getEntryNumberByName(const BGCPString& name);

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

	// Get memory block for a file inside the archive
	bool getFile(size_t fileNum, MemoryBlock& mb);
	bool getFile(const char* fn, MemoryBlock& mb);

	int getFileType(size_t index);
protected:
	std::vector <ArchiveEntry> mEntries;

	void addFile(const BGCPString& name, size_t size, size_t offset, FileType fileType = FileType::unsupported);

	void clearFileEntries();

	void createFileListEntry(const BGCPString& subDirName, size_t index, BGCPString& fileList);
};

////////////////////////////////////////////////////////////////////////////////

// Check if type is an archive
bool isArchiveType(FileType type);

// Open archive
MWArchive* openArchive(const PathChar* archivePath);

// Open single file as Archive
MWArchive* openSingleFileAsArchive(const PathChar* FN);

// Open directory as fake Archive
MWArchive* openDirectoryAsArchive(const PathChar* dir);

// Unpack archive
void unpackArchive(MWArchive* archive, const PathChar* target);

#endif
