// AbstractFileInterfaceNode.h
//
// Andrew Bachmann, 2002
//
// The AbstractFileInterfaceNode class implements
// the common functionality between MediaReader
// and MediaWriter.

#if !defined(_ABSTRACT_FILE_INTERFACE_NODE_H)
#define _ABSTRACT_FILE_INTERFACE_NODE_H

#include <MediaDefs.h>
#include <MediaNode.h>
#include <FileInterface.h>
#include <Controllable.h>
#include <MediaEventLooper.h>
#include <File.h>
#include <Entry.h>
#include <BufferGroup.h>

class AbstractFileInterfaceNode :
    public BFileInterface,
    public BControllable,
    public BMediaEventLooper
{
protected:
virtual ~AbstractFileInterfaceNode(void);

public:

explicit AbstractFileInterfaceNode(
				size_t defaultChunkSize = 8192, // chunk size = 8 KB
				float defaultBitRate = 800000,  // bit rate = 100.000 KB/sec = 5.85 MB/minute
				const flavor_info * info = 0,   // buffer period = 80 milliseconds
				BMessage * config = 0,
				BMediaAddOn * addOn = 0);

virtual status_t InitCheck(void) const;

// see BMediaAddOn::GetConfigurationFor
virtual	status_t GetConfigurationFor(
				BMessage * into_message);

/*************************/
/* begin from BMediaNode */
public:
//	/* this port is what a media node listens to for commands */
// virtual port_id ControlPort(void) const;

virtual	BMediaAddOn* AddOn(
				int32 * internal_id) const;	/* Who instantiated you -- or NULL for app class */

protected:
		/* 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 performance_time);
virtual	void Stop(
				bigtime_t performance_time,
				bool immediate);
virtual	void Seek(
				bigtime_t media_time,
				bigtime_t performance_time);
virtual	void SetRunMode(
				run_mode mode);
virtual	void TimeWarp(
				bigtime_t at_real_time,
				bigtime_t to_performance_time);
virtual	void Preroll(void);
virtual	void SetTimeSource(
				BTimeSource * time_source);

public:
virtual	status_t HandleMessage(
				int32 message,
				const void * data,
				size_t size);
				
protected:
		/* Called when requests have completed, or failed. */
virtual	status_t RequestCompleted(	/* reserved 0 */
				const media_request_info & info);

protected:
virtual		status_t DeleteHook(BMediaNode * node);		/* reserved 1 */

virtual		void NodeRegistered(void);	/* reserved 2 */

public:

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

virtual		status_t AddTimer(
					bigtime_t at_performance_time,
					int32 cookie);

/* end from BMediaNode */
/***********************/

protected:
virtual BParameterWeb * MakeParameterWeb(void);

/*****************************/
/* begin from BFileInterface */
protected:
//included from BMediaNode
//virtual	status_t HandleMessage(
//                int32 message,
//				const void * data,
//				size_t size);

virtual	status_t GetNextFileFormat(
				int32 * cookie,
				media_file_format * out_format);
virtual	void DisposeFileFormatCookie(
				int32 cookie);

virtual	status_t GetDuration(
				bigtime_t * out_time);

virtual	status_t SniffRef(
				const entry_ref & file,
				char * out_mime_type,	/* 256 bytes */
				float * out_quality);

virtual	status_t SetRef(
				const entry_ref & file,
				bool create,
				bigtime_t * out_time) = 0;
				
virtual	status_t SetRef(
				const entry_ref & file,
				uint32 openMode,
				bool create,
				bigtime_t * out_time);
				
virtual	status_t GetRef(
				entry_ref * out_ref,
				char * out_mime_type);

/* end from BFileInterface */
/***************************/

// provided for BAbstractFileInterfaceNodeAddOn
public:
static status_t StaticSniffRef(
				const entry_ref & file,
				char * out_mime_type,	/* 256 bytes */
				float * out_quality);

/****************************/
/* begin from BControllable */

//included from BMediaNode
//virtual	status_t HandleMessage(
//                int32 message,
//				const void * data,
//				size_t size);
public:		
		/* These are alternate methods of accomplishing the same thing as */
		/* connecting to control information source/destinations would. */
virtual	status_t GetParameterValue(
				int32 id,
				bigtime_t * last_change,
				void * value,
				size_t * ioSize);
virtual	void SetParameterValue(
				int32 id,
				bigtime_t when,
				const void * value,
				size_t size);
virtual	status_t StartControlPanel(
				BMessenger * out_messenger);

/* end from BControllable */
/**************************/

public:
		// these three are related:
		// DEFAULT_CHUNK_SIZE = (DEFAULT_BIT_RATE * 1024) * (DEFAULT_BUFFER_PERIOD / 8000000)
		static const int32 DEFAULT_CHUNK_SIZE_PARAM;    // in bytes
		static const int32 DEFAULT_BIT_RATE_PARAM;      // in 1000*kilobits/sec
		static const int32 DEFAULT_BUFFER_PERIOD_PARAM; // milliseconds

private:
		size_t fDefaultChunkSizeParam;				
		bigtime_t fDefaultChunkSizeParamChangeTime;
		float fDefaultBitRateParam;				
		bigtime_t fDefaultBitRateParamChangeTime;
		int32 fDefaultBufferPeriodParam;				
		bigtime_t fDefaultBufferPeriodParamChangeTime;

		// This is used to figure out which parameter to compute
		// when enforcing the above constraint relating the three params
		int32 fLastUpdatedParameter;
		int32 fLeastRecentlyUpdatedParameter;

/********************************/
/* start from BMediaEventLooper */

	protected:
		/* you must override to handle your events! */
		/* you should not call HandleEvent directly */
		virtual void		HandleEvent(	const media_timed_event *event,
											bigtime_t lateness,
											bool realTimeEvent = false);

		/* override to clean up custom events you have added to your queue */
		virtual void		CleanUpEvent(const media_timed_event *event);
		
		/* called from Offline mode to determine the current time of the node */
		/* update your internal information whenever it changes */
		virtual	bigtime_t	OfflineTime();

		/* override only if you know what you are doing! */
		/* otherwise much badness could occur */
		/* the actual control loop function: */
		/* 	waits for messages, Pops events off the queue and calls DispatchEvent */
		virtual void		ControlLoop();

/* end from BMediaEventLooper */
/******************************/

protected:

virtual status_t HandleStart(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false);
virtual status_t HandleSeek(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false);
virtual status_t HandleWarp(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false);
virtual status_t HandleStop(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false);
virtual status_t HandleBuffer(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false) = 0;
virtual status_t HandleDataStatus(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false) = 0;
virtual status_t HandleParameter(
						const media_timed_event *event,
						bigtime_t lateness,
						bool realTimeEvent = false);

public:

static void GetFlavor(flavor_info * outInfo, int32 id);
static void GetFormat(media_format * outFormat);
static void GetFileFormat(media_file_format * outFileFormat);

protected:

virtual status_t AddRequirements(media_format * format);
virtual status_t ResolveWildcards(media_format * format);

// accessors

inline BFile * GetCurrentFile() { return fCurrentFile; }

private:

		AbstractFileInterfaceNode(	/* private unimplemented */
				const AbstractFileInterfaceNode & clone);
		AbstractFileInterfaceNode & operator=(
				const AbstractFileInterfaceNode & clone);				

		status_t fInitCheckStatus;

		BMediaAddOn * fAddOn;
		
		BFile * fCurrentFile;
		entry_ref f_current_ref;
		char f_current_mime_type[B_MIME_TYPE_LENGTH+1];
		
		/* Mmmh, stuffing! */
virtual		status_t _Reserved_AbstractFileInterfaceNode_0(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_1(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_2(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_3(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_4(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_5(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_6(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_7(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_8(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_9(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_10(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_11(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_12(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_13(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_14(void *);
virtual		status_t _Reserved_AbstractFileInterfaceNode_15(void *);

		uint32 _reserved_abstract_file_interface_node_[16];

};

#endif /* _ABSTRACT_FILE_INTERFACE_NODE_H */
