#pragma once
#include "Protocol.h"

namespace storm {
	STORM_PKG(core.io);

	/**
	 * Protocol for creating in-memory "overlays" for some other protocol.
	 *
	 * This is similar to `MemoryProtocol`, but passes through files that are not yet created. It
	 * also emulates equivalence between paths created from the overlay protocol and the original
	 * protocol.
	 *
	 * Note: The implementation is limited to files in a single directory for now. For multiple
	 * directories, it is necessary to create one OverlayProtocol for each directory.
	 *
	 * This is useful for emulating changes to files without modifying content on disk, for example.
	 */
	class OverlayProtocol : public Protocol {
		STORM_CLASS;
	public:
		// Create.
		STORM_CTOR OverlayProtocol(Url *dir);

		// Add/update a file.
		Url *STORM_FN put(Str *name, Buffer content);
		Url *STORM_FN put(Str *name, Str *content);

		// Compare parts.
		virtual Bool STORM_FN partEq(Str *a, Str *b);

		// Hash parts.
		virtual Nat STORM_FN partHash(Str *a);

		// Get child items. Only makes sense on the "root" Url.
		virtual Array<Url *> *STORM_FN children(Url *url);

		// Read a file.
		virtual IStream *STORM_FN read(Url *url);

		// Write a file.
		virtual OStream *STORM_FN write(Url *url);

		// Exists?
		virtual StatType STORM_FN stat(Url *url);

		// To string.
		virtual void STORM_FN toS(StrBuf *to) const;

		// Serialization.
		static SerializedType *STORM_FN serializedType(EnginePtr e);
		static OverlayProtocol *STORM_FN read(ObjIStream *from);
		virtual void STORM_FN write(ObjOStream *to);
		STORM_CTOR OverlayProtocol(ObjIStream *from);

	protected:
		// Compare.
		virtual Bool STORM_FN isEqualTo(const Protocol *o) const;

	private:
		typedef Map<Str *, Buffer> FileMap;

		// All "files" that are overlaid.
		Map<Str *, Buffer> *files;

		// Directory for the original path.
		Url *dir;

		// Check if 'url' is one level below 'dir', and get the file name.
		MAYBE(Str *) isBelow(Url *url) const;
	};

}
