/*
 * Copyright 2010 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef _ARCHIVING_MANAGERS_H
#define _ARCHIVING_MANAGERS_H


#include <map>

#include <String.h>
#include <ObjectList.h>
#include <MessagePrivate.h>

#include <Archivable.h>


#define NULL_TOKEN -42


namespace BPrivate {
namespace Archiving {

extern const char* kManagedField;


class BManagerBase {
public:
	enum manager_type {
		ARCHIVE_MANAGER,
		UNARCHIVE_MANAGER
	};

	BManagerBase(BMessage* topLevelArchive, manager_type type)
		:
		fTopLevelArchive(topLevelArchive),
		fType(type)
	{
		MarkArchive(topLevelArchive);
	}


	static BManagerBase*
	ManagerPointer(const BMessage* constArchive)
	{
		if (!constArchive)
			return NULL;

		BMessage* archive = const_cast<BMessage*>(constArchive);

		return static_cast<BManagerBase*>(
			BMessage::Private(archive).ArchivingPointer());
	}


	static void
	SetManagerPointer(BMessage* archive, BManagerBase* manager)
	{
		BMessage::Private(archive).SetArchivingPointer(manager);
	}


	void
	MarkArchive(BMessage* archive)
	{
		BManagerBase* manager = ManagerPointer(archive);
		if (manager != NULL)
			debugger("Overlapping managed archiving/unarchiving sessions!");

		SetManagerPointer(archive, this);
	}


	void
	UnmarkArchive(BMessage* archive)
	{
		BManagerBase* manager = ManagerPointer(archive);
		if (manager == this)
			SetManagerPointer(archive, NULL);
		else
			debugger("Overlapping managed archiving/unarchiving sessions!");
	}


	static	BArchiveManager*	ArchiveManager(const BMessage* archive);
	static 	BUnarchiveManager*	UnarchiveManager(const BMessage* archive);

protected:
	~BManagerBase()
	{
		UnmarkArchive(fTopLevelArchive);
	}

protected:
			BMessage*			fTopLevelArchive;
			manager_type		fType;
};


class BArchiveManager: public BManagerBase {
public:
								BArchiveManager(const BArchiver* creator);

			status_t			GetTokenForArchivable(BArchivable* archivable,
									int32& _token);

			status_t			ArchiveObject(BArchivable* archivable,
									bool deep, int32& _token);

			bool				IsArchived(BArchivable* archivable);

			status_t			ArchiverLeaving(const BArchiver* archiver,
									status_t err);

			void				Acquire();
			void				RegisterArchivable(
									const BArchivable* archivable);

private:
								~BArchiveManager();

			struct ArchiveInfo;
			typedef std::map<const BArchivable*, ArchiveInfo> TokenMap;

			TokenMap			fTokenMap;
			const BArchiver*	fCreator;
			status_t			fError;
};




class BUnarchiveManager: public BManagerBase {
public:
								BUnarchiveManager(BMessage* topLevelArchive);

			status_t			GetArchivableForToken(int32 token,
									BUnarchiver::ownership_policy owning, 
									BArchivable*& _archivable);

			bool				IsInstantiated(int32 token);

			void				RegisterArchivable(BArchivable* archivable);
			status_t			UnarchiverLeaving(const BUnarchiver* archiver,
									status_t err);
			void				Acquire();

			void				RelinquishOwnership(BArchivable* archivable);
			void				AssumeOwnership(BArchivable* archivable);
private:
								~BUnarchiveManager();

			status_t			_ExtractArchiveAt(int32 index);

			struct ArchiveInfo;

			ArchiveInfo*		fObjects;
			int32				fObjectCount;
			int32				fTokenInProgress;
			int32				fRefCount;
			status_t			fError;
};


} // namespace Archiving
} // namespace BPrivate


#endif	// _ARCHIVING_MANAGERS_H
