//------------------------------------------------------------------------------
//	Copyright (c) 2001-2002, OpenBeOS
//
//	Permission is hereby granted, free of charge, to any person obtaining a
//	copy of this software and associated documentation files (the "Software"),
//	to deal in the Software without restriction, including without limitation
//	the rights to use, copy, modify, merge, publish, distribute, sublicense,
//	and/or sell copies of the Software, and to permit persons to whom the
//	Software is furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//	DEALINGS IN THE SOFTWARE.
//
//	File Name:		Message.h
//	Author(s):		Erik Jaesler (erik@cgsoftware.com)
//					DarkWyrm <bpmagic@columbus.rr.com>
//	Description:	BMessage class creates objects that store data and that
//					can be processed in a message loop.  BMessage objects
//					are also used as data containers by the archiving and 
//					the scripting mechanisms.
//------------------------------------------------------------------------------

#ifndef _MESSAGE_H
#define _MESSAGE_H

// Standard Includes -----------------------------------------------------------

// System Includes -------------------------------------------------------------
#include <BeBuild.h>
#include <OS.h>
#include <Rect.h>
#include <DataIO.h>
#include <Flattenable.h>

#include <AppDefs.h>		/* For convenience */
#include <TypeConstants.h>	/* For convenience */

// Project Includes ------------------------------------------------------------

// Local Includes --------------------------------------------------------------

// Local Defines ---------------------------------------------------------------

// Globals ---------------------------------------------------------------------



class	BBlockCache;
class	BMessenger;
class	BHandler;
class	BString;

// Private or reserved ---------------------------------------------------------
extern "C" void		_msg_cache_cleanup_();
extern "C" int		_init_message_();
extern "C" int		_delete_message_();
//------------------------------------------------------------------------------


// Name lengths and Scripting specifiers ---------------------------------------
#define B_FIELD_NAME_LENGTH			255
#define B_PROPERTY_NAME_LENGTH		255

enum
{
	B_NO_SPECIFIER = 0,
	B_DIRECT_SPECIFIER = 1,
	B_INDEX_SPECIFIER,
	B_REVERSE_INDEX_SPECIFIER,
	B_RANGE_SPECIFIER,
	B_REVERSE_RANGE_SPECIFIER,
	B_NAME_SPECIFIER,
	B_ID_SPECIFIER,

	B_SPECIFIERS_END = 128
	// app-defined specifiers start at B_SPECIFIERS_END+1
};

namespace BPrivate {
	class BMessageBody;
}

// BMessage class --------------------------------------------------------------
class BMessage
{
public:
		uint32		what;

					BMessage();
					BMessage(uint32 what);
					BMessage(const BMessage &a_message);
virtual				~BMessage();

		BMessage	&operator=(const BMessage &msg);

// Statistics and misc info
		status_t	GetInfo(type_code typeRequested, int32 which, char **name,
							type_code *typeReturned, int32 *count = NULL) const;

		status_t	GetInfo(const char *name, type_code *type, int32 *c = 0) const;
		status_t	GetInfo(const char *name, type_code *type, bool *fixed_size) const;

		int32		CountNames(type_code type) const;
		bool		IsEmpty() const;
		bool		IsSystem() const;
		bool		IsReply() const;
		void		PrintToStream() const;

		status_t	Rename(const char *old_entry, const char *new_entry);

// Delivery info
		bool		WasDelivered() const;
		bool		IsSourceWaiting() const;
		bool		IsSourceRemote() const;
		BMessenger	ReturnAddress() const;
		const BMessage	*Previous() const;
		bool		WasDropped() const;
		BPoint		DropPoint(BPoint *offset = NULL) const;

// Replying
		status_t	SendReply(uint32 command, BHandler *reply_to = NULL);
		status_t	SendReply(BMessage *the_reply, BHandler *reply_to = NULL,
							bigtime_t timeout = B_INFINITE_TIMEOUT);
		status_t	SendReply(BMessage *the_reply, BMessenger reply_to,
							bigtime_t timeout = B_INFINITE_TIMEOUT);
	
		status_t	SendReply(uint32 command, BMessage *reply_to_reply);
		status_t	SendReply(BMessage *the_reply, BMessage *reply_to_reply,
							bigtime_t send_timeout = B_INFINITE_TIMEOUT,
							bigtime_t reply_timeout = B_INFINITE_TIMEOUT);

// Flattening data
		ssize_t		FlattenedSize() const;
		status_t	Flatten(char *buffer, ssize_t size) const;
		status_t	Flatten(BDataIO *stream, ssize_t *size = NULL) const;
		status_t	Unflatten(const char *flat_buffer);
		status_t	Unflatten(BDataIO *stream);


// Specifiers (scripting)
		status_t	AddSpecifier(const char *property);
		status_t	AddSpecifier(const char *property, int32 index);
		status_t	AddSpecifier(const char *property, int32 index, int32 range);
		status_t	AddSpecifier(const char *property, const char *name);
		status_t	AddSpecifier(const BMessage *specifier);

		status_t	SetCurrentSpecifier(int32 index);
		status_t	GetCurrentSpecifier(int32 *index, BMessage *specifier = NULL,
							int32 *form = NULL, const char **property = NULL) const;
		bool		HasSpecifiers() const;
		status_t	PopSpecifier();

// Adding data
		status_t	AddRect(const char *name, BRect a_rect);
		status_t	AddPoint(const char *name, BPoint a_point);
		status_t	AddString(const char *name, const char *a_string);
		status_t	AddString(const char *name, const BString& a_string);
		status_t	AddInt8(const char *name, int8 val);
		status_t	AddInt16(const char *name, int16 val);
		status_t	AddInt32(const char *name, int32 val);
		status_t	AddInt64(const char *name, int64 val);
		status_t	AddBool(const char *name, bool a_boolean);
		status_t	AddFloat(const char *name, float a_float);
		status_t	AddDouble(const char *name, double a_double);
		status_t	AddPointer(const char *name, const void *ptr);
		status_t	AddMessenger(const char *name, BMessenger messenger);
		status_t	AddRef(const char *name, const entry_ref *ref);
		status_t	AddMessage(const char *name, const BMessage *msg);
		status_t	AddFlat(const char *name, BFlattenable *obj, int32 count = 1);
		status_t	AddData(const char *name, type_code type, const void *data,
						ssize_t numBytes, bool is_fixed_size = true, int32 count = 1);

// Removing data
		status_t	RemoveData(const char *name, int32 index = 0);
		status_t	RemoveName(const char *name);
		status_t	MakeEmpty();

// Finding data
		status_t	FindRect(const char *name, BRect *rect) const;
		status_t	FindRect(const char *name, int32 index, BRect *rect) const;
		status_t	FindPoint(const char *name, BPoint *pt) const;
		status_t	FindPoint(const char *name, int32 index, BPoint *pt) const;
		status_t	FindString(const char *name, const char **str) const;
		status_t	FindString(const char *name, int32 index, const char **str) const;
		status_t	FindString(const char *name, BString *str) const;
		status_t	FindString(const char *name, int32 index, BString *str) const;
		status_t	FindInt8(const char *name, int8 *value) const;
		status_t	FindInt8(const char *name, int32 index, int8 *val) const;
		status_t	FindInt16(const char *name, int16 *value) const;
		status_t	FindInt16(const char *name, int32 index, int16 *val) const;
		status_t	FindInt32(const char *name, int32 *value) const;
		status_t	FindInt32(const char *name, int32 index, int32 *val) const;
		status_t	FindInt64(const char *name, int64 *value) const;
		status_t	FindInt64(const char *name, int32 index, int64 *val) const;
		status_t	FindBool(const char *name, bool *value) const;
		status_t	FindBool(const char *name, int32 index, bool *value) const;
		status_t	FindFloat(const char *name, float *f) const;
		status_t	FindFloat(const char *name, int32 index, float *f) const;
		status_t	FindDouble(const char *name, double *d) const;
		status_t	FindDouble(const char *name, int32 index, double *d) const;
		status_t	FindPointer(const char *name, void **ptr) const;
		status_t	FindPointer(const char *name, int32 index,  void **ptr) const;
		status_t	FindMessenger(const char *name, BMessenger *m) const;
		status_t	FindMessenger(const char *name, int32 index, BMessenger *m) const;
		status_t	FindRef(const char *name, entry_ref *ref) const;
		status_t	FindRef(const char *name, int32 index, entry_ref *ref) const;
		status_t	FindMessage(const char *name, BMessage *msg) const;
		status_t	FindMessage(const char *name, int32 index, BMessage *msg) const;
		status_t	FindFlat(const char *name, BFlattenable *obj) const;
		status_t	FindFlat(const char *name, int32 index, BFlattenable *obj) const;
		status_t	FindData(const char *name, type_code type,
							const void **data, ssize_t *numBytes) const;
		status_t	FindData(const char *name, type_code type, int32 index,
							const void **data, ssize_t *numBytes) const;

// Replacing data
		status_t	ReplaceRect(const char *name, BRect a_rect);
		status_t	ReplaceRect(const char *name, int32 index, BRect a_rect);
		status_t	ReplacePoint(const char *name, BPoint a_point);
		status_t	ReplacePoint(const char *name, int32 index, BPoint a_point);
		status_t	ReplaceString(const char *name, const char *string);
		status_t	ReplaceString(const char *name, int32 index, const char *string);
		status_t	ReplaceString(const char *name, const BString& string);
		status_t	ReplaceString(const char *name, int32 index, const BString& string);
		status_t	ReplaceInt8(const char *name, int8 val);
		status_t	ReplaceInt8(const char *name, int32 index, int8 val);
		status_t	ReplaceInt16(const char *name, int16 val);
		status_t	ReplaceInt16(const char *name, int32 index, int16 val);
		status_t	ReplaceInt32(const char *name, int32 val);
		status_t	ReplaceInt32(const char *name, int32 index, int32 val);
		status_t	ReplaceInt64(const char *name, int64 val);
		status_t	ReplaceInt64(const char *name, int32 index, int64 val);
		status_t	ReplaceBool(const char *name, bool a_bool);
		status_t	ReplaceBool(const char *name, int32 index, bool a_bool);
		status_t	ReplaceFloat(const char *name, float a_float);
		status_t	ReplaceFloat(const char *name, int32 index, float a_float);
		status_t	ReplaceDouble(const char *name, double a_double);
		status_t	ReplaceDouble(const char *name, int32 index, double a_double);
		status_t	ReplacePointer(const char *name, const void *ptr);
		status_t	ReplacePointer(const char *name,int32 index,const void *ptr);
		status_t	ReplaceMessenger(const char *name, BMessenger messenger);
		status_t	ReplaceMessenger(const char *name, int32 index, BMessenger msngr);
		status_t	ReplaceRef(	const char *name,const entry_ref *ref);
		status_t	ReplaceRef(	const char *name, int32 index, const entry_ref *ref);
		status_t	ReplaceMessage(const char *name, const BMessage *msg);
		status_t	ReplaceMessage(const char *name, int32 index, const BMessage *msg);
		status_t	ReplaceFlat(const char *name, BFlattenable *obj);
		status_t	ReplaceFlat(const char *name, int32 index, BFlattenable *obj);
		status_t	ReplaceData(const char *name, type_code type,
								const void *data, ssize_t data_size);
		status_t	ReplaceData(const char *name, type_code type, int32 index,
								const void *data, ssize_t data_size);

		void		*operator new(size_t size);
		void		*operator new(size_t, void* p);
		void		operator delete(void *ptr, size_t size);

// Private, reserved, or obsolete ----------------------------------------------
		bool		HasRect(const char *, int32 n = 0) const;
		bool		HasPoint(const char *, int32 n = 0) const;
		bool		HasString(const char *, int32 n = 0) const;
		bool		HasInt8(const char *, int32 n = 0) const;
		bool		HasInt16(const char *, int32 n = 0) const;
		bool		HasInt32(const char *, int32 n = 0) const;
		bool		HasInt64(const char *, int32 n = 0) const;
		bool		HasBool(const char *, int32 n = 0) const;
		bool		HasFloat(const char *, int32 n = 0) const;
		bool		HasDouble(const char *, int32 n = 0) const;
		bool		HasPointer(const char *, int32 n = 0) const;
		bool		HasMessenger(const char *, int32 n = 0) const;
		bool		HasRef(const char *, int32 n = 0) const;
		bool		HasMessage(const char *, int32 n = 0) const;
		bool		HasFlat(const char *, const BFlattenable *) const;
		bool		HasFlat(const char *,int32 ,const BFlattenable *) const;
		bool		HasData(const char *, type_code , int32 n = 0) const;
		BRect		FindRect(const char *, int32 n = 0) const;
		BPoint		FindPoint(const char *, int32 n = 0) const;
		const char	*FindString(const char *, int32 n = 0) const;
		int8		FindInt8(const char *, int32 n = 0) const;
		int16		FindInt16(const char *, int32 n = 0) const;
		int32		FindInt32(const char *, int32 n = 0) const;
		int64		FindInt64(const char *, int32 n = 0) const;
		bool		FindBool(const char *, int32 n = 0) const;
		float		FindFloat(const char *, int32 n = 0) const;
		double		FindDouble(const char *, int32 n = 0) const;

		class Private;

private:

friend class	BMessageQueue;
friend class	BMessenger;
friend class	BApplication;
friend class	Private;

friend			void		_msg_cache_cleanup_();
friend			BMessage 	*_reconstruct_msg_(uint32,uint32,uint32);
friend inline	void		_set_message_target_(BMessage *, int32, bool);
friend inline	void		_set_message_reply_(BMessage *, BMessenger);
friend inline	int32		_get_message_target_(BMessage *);
friend inline	bool		_use_preferred_target_(BMessage *);

					// deprecated
					BMessage(BMessage *a_message);
					
virtual	void		_ReservedMessage1();
virtual	void		_ReservedMessage2();
virtual	void		_ReservedMessage3();

		void		init_data();
		status_t	flatten_hdr(BDataIO *stream) const;
		status_t	unflatten_hdr(BDataIO *stream, bool& swap);
		status_t	flatten_target_info(BDataIO *stream,
										ssize_t size,
										uchar flags) const;
		status_t	real_flatten(char *result,
								ssize_t size) const;
		status_t	real_flatten(BDataIO *stream) const;
		char		*stack_flatten(char *stack_ptr,
									ssize_t stack_size,
									bool incl_reply,
									ssize_t *size = NULL) const;
		ssize_t		calc_size(uchar flags) const;
		ssize_t		calc_hdr_size(uchar flags) const;
		ssize_t		min_hdr_size() const;
		status_t	nfind_data(	const char *name,
								type_code type,
								int32 index,
								const void **data,
								ssize_t *data_size) const;
		status_t	copy_data(	const char *name,
								type_code type,
								int32 index,
								void *data,
								ssize_t data_size) const;

		status_t	_send_(port_id port,
							int32 token,
							bool preferred,
							bigtime_t timeout,
							bool reply_required,
							BMessenger &reply_to) const;
		status_t	send_message(port_id port,
								team_id port_owner,
								int32 token,
								bool preferred,
								BMessage *reply,
								bigtime_t send_timeout,
								bigtime_t reply_timeout) const;
		enum		{ sNumReplyPorts = 3 };
static	port_id		sReplyPorts[sNumReplyPorts];
static	long		sReplyPortInUse[sNumReplyPorts];
static	int32		sGetCachedReplyPort();

friend	int _init_message_();
friend	int _delete_message_();
static	BBlockCache	*sMsgCache;

		struct dyn_array {
			int32		fLogicalBytes;
			int32		fPhysicalBytes;
			int32		fChunkSize;		
			int32		fCount;
			int32		fEntryHdrSize;	
		};

		struct entry_hdr  : public dyn_array {
			entry_hdr	*fNext;
			uint32		fType;
			uchar		fNameLength;	
			char		fName[1];
		};

		struct var_chunk {
			int32	fDataSize;				
			char	fData[1];
		};

		entry_hdr 	*entry_find(const char *name, uint32 type,status_t *result=NULL) const;
		void 		entry_remove(entry_hdr *entry);
		
		void		*da_create(int32 header_size, int32 chunk_size,
								bool fixed, int32 nchunks);
		status_t	da_add_data(dyn_array **da, const void *data, int32 size);
		void		*da_find_data(dyn_array *da, int32 index,
									int32 *size = NULL) const;
		status_t	da_delete_data(dyn_array **pda, int32 index);
		status_t	da_replace_data(dyn_array **pda, int32 index,
									const void *data, int32 dsize);
		int32		da_calc_size(int32 hdr_size, int32 chunksize,
								bool is_fixed, int32 nchunks) const;
		void		*da_grow(dyn_array **pda, int32 increase);
		void		da_dump(dyn_array *da);

		int32		da_chunk_hdr_size() const
						{ return sizeof(int32); }
		int32		da_chunk_size(var_chunk *v) const
						{ return (v->fDataSize + da_chunk_hdr_size() + 7) & ~7; }
		var_chunk	*da_first_chunk(dyn_array *da) const
						{ return (var_chunk *) da_start_of_data(da); }
		var_chunk	*da_next_chunk(var_chunk *v) const
						{ return (var_chunk *) (((char*) v) + da_chunk_size(v)); }
		var_chunk	*da_chunk_ptr(void *data) const
						{ return (var_chunk*) (((char *) data) - da_chunk_hdr_size()); }

		int32		da_pad_8(int32 val) const
						{ return (val + 7) & ~7; }
		int32		da_total_size(dyn_array *da) const
						{ return (int32)sizeof(dyn_array) + da->fEntryHdrSize +
											da->fPhysicalBytes; }
		int32		da_total_logical_size(dyn_array *da) const
						{ return (int32)sizeof(dyn_array) + da->fEntryHdrSize +
											da->fLogicalBytes; }
		char		*da_start_of_data(dyn_array *da) const
						{ return ((char *) da) + (sizeof(dyn_array) +
											da->fEntryHdrSize); }
		bool		da_is_mini_data(dyn_array *da) const
						{ return ((da->fLogicalBytes <= (int32) UCHAR_MAX) &&
											(da->fCount <= (int32) UCHAR_MAX));}
		void		da_swap_var_sized(dyn_array *da);
		void		da_swap_fixed_sized(dyn_array *da);

		BMessage			*link;
		int32				fTarget;	
		BMessage			*fOriginal;
		uint32				fChangeCount;
		int32				fCurSpecifier;
		uint32				fPtrOffset;

		// ejaesler: Stealing one for my whacky BMessageBody l33tness
		uint32				_reserved[2];
		BPrivate::BMessageBody*	fBody;

		BMessage::entry_hdr	*fEntries;

		struct {
			port_id				port;
			int32				target;
			team_id				team;
			bool				preferred;
		} fReplyTo;

		bool				fPreferred;
		bool				fReplyRequired;
		bool				fReplyDone;
		bool				fIsReply;
		bool				fWasDelivered;
		bool				fReadOnly;
		bool				fHasSpecifiers;	
};

//------------------------------------------------------------------------------

#endif	// _MESSAGE_H

/*
 * $Log $
 *
 * $Id  $
 *
 */

