/*
 * Copyright 2009-2012, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef _MEDIA_NODE_H
#define _MEDIA_NODE_H


#include <MediaDefs.h>
#include <Point.h>

#include <new>


class BBufferConsumer;
class BBufferProducer;
class BControllable;
class BFileInterface;
class BMediaAddOn;
class BTimeSource;


class media_node {
public:
								media_node();
								~media_node();

			media_node_id		node;
			port_id				port;
			uint32				kind;

	static	media_node			null;

private:
			uint32				_reserved_[3];
};


struct media_input {
								media_input();
								~media_input();

			media_node			node;
			media_source		source;
			media_destination	destination;
			media_format		format;
			char				name[B_MEDIA_NAME_LENGTH];

private:
			uint32				_reserved_media_input_[4];
};


struct media_output {
								media_output();
								~media_output();

			media_node			node;
			media_source		source;
			media_destination	destination;
			media_format		format;
			char				name[B_MEDIA_NAME_LENGTH];

private:
			uint32				_reserved_media_output_[4];
};


struct live_node_info {
								live_node_info();
								~live_node_info();

			media_node			node;
			BPoint				hint_point;
			char				name[B_MEDIA_NAME_LENGTH];

private:
			char				reserved[160];
};


struct media_request_info {
			enum what_code {
				B_SET_VIDEO_CLIPPING_FOR = 1,
				B_REQUEST_FORMAT_CHANGE,
				B_SET_OUTPUT_ENABLED,
				B_SET_OUTPUT_BUFFERS_FOR,

				B_FORMAT_CHANGED = 4097
			};

			what_code			what;
			int32				change_tag;
			status_t			status;
			void*				cookie;
			void*				user_data;
			media_source		source;
			media_destination	destination;
			media_format		format;

			uint32				_reserved_[32];
};


struct media_node_attribute {
			enum {
				B_R40_COMPILED = 1,
				B_USER_ATTRIBUTE_NAME = 0x1000000,
				B_FIRST_USER_ATTRIBUTE
			};

			uint32				what;
			uint32				flags;
			int64				data;
};


namespace BPrivate {
	namespace media {
		class TimeSourceObject;
		class SystemTimeSourceObject;
		class BMediaRosterEx;
	}
} // BPrivate::media


/*!	BMediaNode is the indirect base class for all Media Kit participants.
	However, you should use the more specific BBufferConsumer, BBufferProducer
	and others rather than BMediaNode directly. It's OK to multiply inherit.
*/
class BMediaNode {
protected:
	// NOTE: Call Release() to destroy a node.
	virtual								~BMediaNode();

public:
			enum run_mode {
				B_OFFLINE = 1,
					// This mode has no realtime constraint.
				B_DECREASE_PRECISION,
					// When late, try to catch up by reducing quality.
				B_INCREASE_LATENCY,
					// When late, increase the presentation time offset.
				B_DROP_DATA,
					// When late, try to catch up by dropping buffers.
				B_RECORDING
					// For nodes on the receiving end of recording.
					// Buffers will always be late.
			};

#if 0  // HoG_GENODE
			BMediaNode*			Acquire();
			BMediaNode*			Release();

			const char*			Name() const;
			media_node_id		ID() const;
			uint64				Kinds() const;
			media_node			Node() const;
			run_mode			RunMode() const;
			BTimeSource*		TimeSource() const;

	// ID of the port used to listen to control messages.
	virtual	port_id				ControlPort() const;

	// Who instantiated this node or NULL for application internal class.
	virtual	BMediaAddOn*		AddOn(int32* internalID) const = 0;

	// Message constants which will be sent to anyone watching the
	// MediaRoster. The message field "be:node_id" will contain the node ID.
			enum node_error {
				// Note that these belong with the notifications in
				// MediaDefs.h! They are here to provide compiler type
				// checking in ReportError().
				B_NODE_FAILED_START					= 'TRI0',
				B_NODE_FAILED_STOP					= 'TRI1',
				B_NODE_FAILED_SEEK					= 'TRI2',
				B_NODE_FAILED_SET_RUN_MODE			= 'TRI3',
				B_NODE_FAILED_TIME_WARP				= 'TRI4',
				B_NODE_FAILED_PREROLL				= 'TRI5',
				B_NODE_FAILED_SET_TIME_SOURCE_FOR	= 'TRI6',
				B_NODE_IN_DISTRESS					= 'TRI7'
				// What field 'TRIA' and up are used in MediaDefs.h
			};

protected:
	// Sends one of the above codes to anybody who's watching. You can
	// provide an optional message with additional information.
			status_t			ReportError(node_error what,
									const BMessage* info = NULL);

	// When you've handled a stop request, call this function. If anyone is
	// listening for stop information from you, they will be notified.
	// Especially important for offline capable Nodes.
			status_t			NodeStopped(bigtime_t performanceTime);
			void				TimerExpired(bigtime_t notifyPerformanceTime,
									int32 cookie, status_t error = B_OK);

	// NOTE: Constructor initializes the reference count to 1.
	explicit					BMediaNode(const char* name);

				status_t		WaitForMessage(bigtime_t waitUntil,
									uint32 flags = 0, void* _reserved_ = 0);

	// These don't return errors; instead, they use the global error condition
	// reporter. A node is required to have a queue of at least one pending
	// command (plus TimeWarp) and is recommended to allow for at least one
	// pending command of each type. Allowing an arbitrary number of
	// outstanding commands might be nice, but apps cannot depend on that
	// happening.
	virtual	void				Start(bigtime_t atPerformanceTime);
	virtual	void				Stop(bigtime_t atPerformanceTime,
									bool immediate);
	virtual	void				Seek(bigtime_t toMediaTime,
									bigtime_t atPerformanceTime);
	virtual	void				SetRunMode(run_mode mode);
	virtual	void				TimeWarp(bigtime_t atRealTime,
									bigtime_t toPerformanceTime);
	virtual	void				Preroll();
	virtual	void				SetTimeSource(BTimeSource* timeSource);

public:
	virtual	status_t			HandleMessage(int32 message, const void* data,
									size_t size);

	// Call this with messages you and your superclasses don't recognize.
			void				HandleBadMessage(int32 code,
									const void* buffer, size_t size);

	// Called from derived system classes; you don't need to
			void				AddNodeKind(uint64 kind);

	// These just call the default global versions for now.
			void*				operator new(size_t size);
			void*				operator new(size_t size,
									const std::nothrow_t&) throw();
			void				operator delete(void* ptr);
			void				operator delete(void* ptr,
									const std::nothrow_t&) throw();

protected:
	// Hook method which is called when requests have completed, or failed.
	virtual	status_t			RequestCompleted(
									const media_request_info & info);

	virtual	status_t			DeleteHook(BMediaNode* node);

	virtual	void				NodeRegistered();

public:

	// Fill out your attributes in the provided array, returning however
	// many you have.
	virtual	status_t			GetNodeAttributes(
									media_node_attribute* _attributes,
									size_t inMaxCount);

	virtual	status_t			AddTimer(bigtime_t atPerformanceTime,
									int32 cookie);

private:
			friend class BTimeSource;
			friend class BMediaRoster;
			friend class BBufferProducer;
			friend class BPrivate::media::TimeSourceObject;
			friend class BPrivate::media::SystemTimeSourceObject;
			friend class BPrivate::media::BMediaRosterEx;

			// Deprecated in BeOS R4.1
			int32				IncrementChangeTag();
			int32				ChangeTag();
			int32				MintChangeTag();
			status_t			ApplyChangeTag(int32 previouslyReserved);

private:
	// FBC padding and forbidden methods
			status_t			_Reserved_MediaNode_0(void*);
				// RequestCompletionHook()
			status_t			_Reserved_MediaNode_1(void*);
				// DeleteHook()
			status_t			_Reserved_MediaNode_2(void*);
				// NodeRegistered()
			status_t			_Reserved_MediaNode_3(void*);
				// GetNodeAttributes()
			status_t			_Reserved_MediaNode_4(void*);
				// AddTimer()
	virtual	status_t			_Reserved_MediaNode_5(void*);
	virtual	status_t			_Reserved_MediaNode_6(void*);
	virtual	status_t			_Reserved_MediaNode_7(void*);
	virtual	status_t			_Reserved_MediaNode_8(void*);
	virtual	status_t			_Reserved_MediaNode_9(void*);
	virtual	status_t			_Reserved_MediaNode_10(void*);
	virtual	status_t			_Reserved_MediaNode_11(void*);
	virtual	status_t			_Reserved_MediaNode_12(void*);
	virtual	status_t			_Reserved_MediaNode_13(void*);
	virtual	status_t			_Reserved_MediaNode_14(void*);
	virtual	status_t			_Reserved_MediaNode_15(void*);

								BMediaNode();
								BMediaNode(const BMediaNode& other);
			BMediaNode&			operator=(const BMediaNode& other);

private:
								BMediaNode(const char* name,
									media_node_id id, uint32 kinds);

			void				_InitObject(const char* name,
									media_node_id id, uint64 kinds);

private:
			media_node_id		fNodeID;
			BTimeSource*		fTimeSource;
			int32				fRefCount;
			char				fName[B_MEDIA_NAME_LENGTH];
			run_mode			fRunMode;

			int32				_reserved[2];

			uint64				fKinds;
			media_node_id		fTimeSourceID;

			BBufferProducer*	fProducerThis;
			BBufferConsumer*	fConsumerThis;
			BFileInterface*		fFileInterfaceThis;
			BControllable*		fControllableThis;
			BTimeSource*		fTimeSourceThis;

			bool				_reservedBool[4];

	mutable	port_id				fControlPort;

			uint32				_reserved_media_node_[8];

protected:
	static	int32				NewChangeTag();
		// for use by BBufferConsumer, mostly

private:
	// NOTE: Dont' rename this one, it's static and needed for binary
	// compatibility
	static	int32 _m_changeTag;
		// not to be confused with _mChangeCount
#endif  // ~HoG_GENODE
};


#endif // _MEDIA_NODE_H
