/* This file is part of Fenix. Copyright Sven Karlsson 1996-1999 

   This file, or any part of it, _may_ not be used in any other 
   project,commercial or  noncommercial, without a written 
   permission by Sven Karlsson.

   However, members of the Fenix developer list are allowed to 
   modify this file as long as the modifications are not made
   public and all modifications are sent to Sven Karlsson.

   Note: This _will_ go away and will be replaced by some sort
   of public licence. Fenix will definately be some sort of
   free software eventually.

   Sven Karlsson can be reached at sven@it.lth.se
 */

#ifndef FOOPY_FOOPY_H
#define FOOPY_FOOPY_H

#include "../base/types.h"
#include <setjmp.h>

typedef struct base_object
{
 struct base_object   *next;
 struct base_object   *prev;
 struct base_class   *my_class;
} FENIX_BASE_OBJECT;

typedef struct tag_item
{
 UINT32 tag;
 INT32  value;
};

typedef union oo_args
{
 UINT32           value;
 struct tag_item  *tags;
 void             *any_ptr;
} FOOPY_ARGS;

typedef struct selector
{
 UINT32				accel_offset;
 UINT32				FGID;
 char				*name_type;
 struct selector    *name_hash_next;
 struct selector    *FGID_hash_next;
} *SEL;

typedef struct
{
 IPTR REGARGS (*implementation)(struct base_class *the_class,
	                               void              *object,
							                         SEL               selector,
							                         void              *args);
} IMP;

typedef struct base_class
{
 IMP               dispatcher;
 struct base_class *super_class;
 char              *name;
 char              *types;            /* types of the member variables. Used in serialization methods */
 UINT32            inst_off;
 union
 {
  UINT32            instance_count;
  struct base_class *class_instance;	 /* only used in the meta class */	
 } count_or_class;
 UINT16            inst_size;
 UINT16            subclass_count;
 UINT16            nbr_of_accellerated_methods;
 UINT16            flags;
#define FENIX_BASE_CLASS_flags_instanced	 1	/* only applies to Meta Classes */
#define FENIX_BASE_CLASS_flags_registered	2
} FENIX_BASE_CLASS;

typedef FENIX_BASE_CLASS  *CLASS;
typedef FENIX_BASE_OBJECT *OBJECT;

typedef struct exception_entry
{
 struct exception_entry *next;				       /* next "catch frame" */
 UINT32                  catch_entries;		/* nbr of handled exceptions */
 UINT32                 *catch_vector;		 /* vector of handled exceptionIds */
 jmp_buf                 env;				        /* longjmp environment */
} FOOPY_EXCEPTION_ENTRY;

/*****************************************************************

 FOOPY macros

 *****************************************************************/

#define INST_DATA(a,b) ((void *)(((char *)a)+(((FENIX_BASE_CLASS *)(b))->inst_off))) 
 /* INST_DATA is strictly speaking only for implementors of classes */

#define get_class(a) ((((FENIX_BASE_OBJECT *)(a))-1)->my_class)
 /* get_class(object) */

#define invoke_imp_basic_aid(a,b,c,d,e)((*((a).implementation))((FENIX_BASE_CLASS*)(b),(void *)(c),(SEL)(d),(void *)(e)))
#define invoke_imp_basic(a,b,c,d,e) (invoke_imp_basic_aid((/*(IMP)*/(a)),(b),(c),(d),(e)))
 /* invoke_imp_basic(imp,class,object,selector,args) */
#define invoke_imp(a,b,c,d) ((a),get_class((b)),(b),(c),(d)))
 /* invoke_imp(imp,object,selector,args) */
#define lookup_imp(a,b) (*((IMP *)(((char *)(a))-(((SEL) (b))->accel_offset)))) 
 /* lookup_imp(class,selector) */

#define invoke_method_basic(a,b,c,d) (invoke_imp_basic(lookup_imp((a),(c)),(a),(b),(c),(d)))
 /* invoke_method_basic(class,object,selector,args) */
#define invoke_method(a,b,c) (invoke_method_basic(get_class((a)),(a),(b),(c)))
 /* invoke_method(object,selector,args) */

#define get_super(a) (((FENIX_BASE_CLASS*) (a))->super_class)
 /* get_super(class) */
#define invoke_super_method_basic(a,b,c,d) (invoke_method_basic(get_super((a)),(b),(c),(d)))
 /* invoke_super_method_basic(class,object,selector,args) */
#define invoke_super_method(a,b,c) (invoke_super_method_basic(get_class((a)),(a),(b),(c)))
 /* invoke_super_method(object,selector,args) */

#define invoke_class_method_basic(a,b,c,d) (invoke_method_basic(get_class((a)),(b),(c),(d)))
 /* invoke_class_method_basic(class,object,selector,args) */
#define invoke_class_method(a,b,c) (invoke_method(get_class((a)),(b),(c)))
 /* invoke_class_method(class,selector,args) */

#define F_DURING(a,b) {void *localException; FOOPY_EXCEPTION_ENTRY FOOPYexception_entry; FOOPYexception_entry.catch_entries=(a); FOOPYexception_entry.catch_vector=(b); FOOPY_add_to_exception_chain(&FOOPYexception_entry); if (!(localException=setjmp(FOOPYexception_entry.env))) { 
 /* a is number of exceptions to catch 
    b is a vector of exceptions
	    if a!=0 and b==0 then all exceptions will be handled by the handler.
	   localExcpetion is defined and can be used to check which exception was raised.
  */
#define F_REMOVE_EXCEPTION_ENTRY {FOOPY_set_exception_chain(FOOPYexception_entry.next);}
#define F_VALUERETURN(a) {F_REMOVE_EXCEPTION_ENTRY return((a));}
 /* returns a to the caller and do all exception cleanup */
#define F_VOIDRETURN {F_REMOVE_EXCEPTION_ENTRY return;}
#define F_HANDLER } else {
#define F_ENDHANDLER } F_REMOVE_EXCEPTION_ENTRY}
#define FOOPY_GET_CURR_EXCEPTION_CHAIN(a) {(a)=FOOPY_exception_chain;} 
 /* the above is only used for the raise method in FException.
    It will soon change into a proper multithread aware one */

/******************************************************************
 FOOPY functions
 ******************************************************************/

FENIX_BASE_CLASS *open_FOOPY_library(SEL *lookup_selector_by_name);
 /* returns the root class as well as the "lookup_selector_by_name" selector
    0 is returned if the library couldn't be opened for some reason */

VOID FOOPY_add_to_exception_chain(FOOPY_EXCEPTION_ENTRY *entry);
 /* adds the entry to the current thread's exception chain */
VOID FOOPY_set_exception_chain(FOOPY_EXCEPTION_ENTRY *entry);
 /* sets the current thread's exception chain */

/**********************************************************************
 FOOPY Types and Method signatures

 Each method on FOOPY has a text string containing the method name as 
 well as the types of return values and parameters. These strings are
 called signatures and are built using a similar grammar to the one Java
 uses. Here is a pseudo-EBNF grammar.

 Signature := Method_name Types
 Types := '(' Parameters ')' Return_type
 Object_members := Type*
 Parameters := Type*
 Return_type := Type
 Type := (('*'+)|0)(Simple_type | Struct | Union | FGID | Object | Class | Imp | Selector | Vector)
 Simple_type := ('U'|0)('B'|'D'|'F'|'I'|'J'|'S'|'Z')
 Struct := '{' Type+ '}'
 Union := '<' Type+ '>'
 FGID := 'G'
 Object := 'L' (Class_name|0) ';' 
 Class := 'M' (Meta_class_name|0) ';' 
 Imp := 'R'
 Selector := 'A'
 Vector := '[' Type

 Some notes:
 Type: The 'P' denotes that the type is a pointer. Several '*' is used
       to denote additional levels of indirection.
 Simple_type: The 'U'  is used to denote signess. A 'U' means that the
       type is unsigned. The default signess is signed. The following
	   character specifies the actual type:
	    'B' 8-bit integer
		'D' 32-bit IEEE floating point
		'F' 64-bit IEEE floating point
		'I' 32-bit integer
		'J' 64-bit integer
		'S' 16-bit integer
		'Z' boolean
		'V' void

 All strings are in 8-bit UTF as used in Java.

 The Object_members rule is used for the object member type string present
 in all class objects.

***********************************************************************/


/******************************************************************
 FOOPY FGIDs

 NOTE: FOOPY FGIDs are allocated in 1024 FGID chuncs by emailing sven@it.lth.se
       all FGIDs from 0x00000000 to 0x00ffffff are allocated to Fenix

       Complete signatures are only used when there are several differnt
	   methods with the same name. The first method added is without type
	   the second is. The signature strings, however, always contain the
	   full signature. The FGID identifier may also be munged so that only
	   characters allowed in C-identifiers are used.
 ******************************************************************/

#define FOOPY_FGID(a)												   ((UINT32) (a))
#define FOOPY_dispatch												  FOOPY_FGID(0)
#define FOOPY_init													     FOOPY_FGID(1)
#define FOOPY_hiddenInit										  FOOPY_FGID(2)
#define FOOPY_alloc													    FOOPY_FGID(3)
#define FOOPY_hiddenAlloc									  FOOPY_FGID(4)
#define FOOPY_deinit												    FOOPY_FGID(5)
#define FOOPY_dealloc               FOOPY_FGID(6)
#define FOOPY_lookupClass											FOOPY_FGID(7)
#define FOOPY_lookupSelector								FOOPY_FGID(8)
#define FOOPY_lookupSelector_G_A				FOOPY_FGID(9)
#define FOOPY_registerClass									FOOPY_FGID(10)
#define FOOPY_registerSelector						FOOPY_FGID(11)
#define FOOPY_initNewMetaClass		 			FOOPY_FGID(12)
#define FOOPY_initNewClass										FOOPY_FGID(13)
#define FOOPY_exceptionId											FOOPY_FGID(14)
#define FOOPY_init_UI												   FOOPY_FGID(15)
#define FOOPY_raise													    FOOPY_FGID(16)

/******************************************************************
 FOOPY Exception GIDs (EGIDs)

  NOTE: FOOPY EGIDs are allocated in 1024 EGID chuncs by emailing sven@it.lth.se
       all EGIDs from 0x00000000 to 0x00ffffff are allocated to Fenix
*******************************************************************/

#define FOOPY_EGID(a)												           ((UINT32) (a))
#define FOOPY_MallocException										     FOOPY_EGID(1)
#define FOOPY_GenericException										    FOOPY_EGID(2)
#define FOOPY_RangeException										      FOOPY_EGID(3)
#define FOOPY_InvalidArgumentException						FOOPY_EGID(4)
#define FOOPY_UnimplementedMethodException		FOOPY_EGID(5)

/**********************************************************************
 FOOPY arg structs

 Most methods take a pointer to a struct as argument. The struct holds
 additional arguments. Below are the structs that the basic system
 classes use.
***********************************************************************/

typedef struct
{
 char     *name_type;		/* name of the selector */
 UINT32				FGID;			    /* the unique FGID of the selector */
 CLASS				 the_class;		/* if not NULL then the selector will be registered
									                 to the system as an accelerated method if possible */
} FOOPY_registerSelector_args;

typedef struct
{
 UINT32				FGID;			      /* the unique FGID of the selector corresponding to the method */
 char     *name_type;		  /* name/type of the method. May be NULL if you are
									                   sure the selector is already registered */
 IMP				   method;
 BOOL      accellerated;	/* TRUE if the method is accellerated */
} FOOPY_initNewClass_method;

typedef struct
{
 char				*name;            /* name of the Meta Class */
 CLASS				super_class;     /* class object not meta class */
 char    *types;           /* member variable types */
 UINT32			inst_size;		     /* class size */
 UINT32   nbr_of_methods;
 FOOPY_initNewClass_method *methods;
} FOOPY_initNewMetaClass_args;

typedef struct
{
 UINT32				inst_size;        /* object size */
 char     *types;            /* member variable types */
 UINT32    nbr_of_methods;
 FOOPY_initNewClass_method *methods;
} FOOPY_initNewClass_args;

#endif