/*
 GNU Maverik - a system for managing display and interaction in 
               Virtual Environment applications.
 Copyright (C) 1999-2001 Advanced Interfaces Group

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA


 The authors can be contacted via:
 www   - http://aig.cs.man.ac.uk
 email - maverik@aig.cs.man.ac.uk
 mail  - Advanced Interfaces Group, Room 2.94, Kilburn Building, 
         University of Manchester, Manchester, M13 9PL, UK
*/

#ifndef _MAV_SMS_INCLUDE
#define _MAV_SMS_INCLUDE

#ifdef __cplusplus
extern "C" {
#endif

/* Callbacks for SMS's */

/* Add object to SMS */

extern MAV_SMSCallback *mav_SMSCallback_objectAdd;
typedef int (*MAV_SMSCallbackObjectAddFn)(MAV_SMS *, MAV_object *);
void mav_SMSCallbackObjectAddSet(MAV_SMSClass *sc, MAV_SMSCallbackObjectAddFn fn);
int mav_SMSCallbackObjectAddExec(MAV_SMS *s, MAV_object *o);
int mav_SMSObjectAdd(MAV_SMS *s, MAV_object *o);

/* Intersect objects */

extern MAV_SMSCallback *mav_SMSCallback_intersect;
typedef int (*MAV_SMSCallbackIntersectFn)(MAV_SMS *, MAV_window *, MAV_line *, MAV_objectIntersection *, MAV_object **);
void mav_SMSCallbackIntersectSet(MAV_SMSClass *sc, MAV_SMSCallbackIntersectFn fn);
int mav_SMSCallbackIntersectExec(MAV_SMS *s, MAV_window *w, MAV_line ln, MAV_objectIntersection *oi, MAV_object **o);

/* Reset pointer */

extern MAV_SMSCallback *mav_SMSCallback_pointerReset;
typedef int (*MAV_SMSCallbackPointerResetFn)(MAV_SMS *);
void mav_SMSCallbackPointerResetSet(MAV_SMSClass *sc, MAV_SMSCallbackPointerResetFn fn);
int mav_SMSCallbackPointerResetExec(MAV_SMS *s);

/* Push pointer */

extern MAV_SMSCallback *mav_SMSCallback_pointerPush;
typedef int (*MAV_SMSCallbackPointerPushFn)(MAV_SMS *);
void mav_SMSCallbackPointerPushSet(MAV_SMSClass *sc, MAV_SMSCallbackPointerPushFn fn);
int mav_SMSCallbackPointerPushExec(MAV_SMS *s);

/* Pop pointer */

extern MAV_SMSCallback *mav_SMSCallback_pointerPop;
typedef int (*MAV_SMSCallbackPointerPopFn)(MAV_SMS *);
void mav_SMSCallbackPointerPopSet(MAV_SMSClass *sc, MAV_SMSCallbackPointerPopFn fn);
int mav_SMSCallbackPointerPopExec(MAV_SMS *s);

/* Next object */

extern MAV_SMSCallback *mav_SMSCallback_objectNext;
typedef int (*MAV_SMSCallbackObjectNextFn)(MAV_SMS *, MAV_object **);
void mav_SMSCallbackObjectNextSet(MAV_SMSClass *sc, MAV_SMSCallbackObjectNextFn fn);
int mav_SMSCallbackObjectNextExec(MAV_SMS *s, MAV_object **o);

/* ExecuteFn */

typedef void (*MAV_SMSExecFnFn)(MAV_object *, MAV_drawInfo *, void *);

typedef struct {
  MAV_SMSExecFnFn fn;
  int nocalc;
  void *params;
} MAV_SMSExecFn;

extern MAV_SMSCallback *mav_SMSCallback_execFn;
typedef int (*MAV_SMSCallbackExecFnFn)(MAV_SMS *, MAV_drawInfo *, MAV_SMSExecFn *);
void mav_SMSCallbackExecFnSet(MAV_SMSClass *sc, MAV_SMSCallbackExecFnFn fn);
int mav_SMSCallbackExecFnExec(MAV_SMS *s, MAV_drawInfo *di, MAV_SMSExecFn *fn);

/* Empty */

extern MAV_SMSCallback *mav_SMSCallback_empty;
typedef int (*MAV_SMSCallbackEmptyFn)(MAV_SMS *, int *);
void mav_SMSCallbackEmptySet(MAV_SMSClass *sc, MAV_SMSCallbackEmptyFn fn);
int mav_SMSCallbackEmptyExec(MAV_SMS *s, int o);



/* Optional callbacks (if not defined are inefficiently simulated with reset and next) */

/*  Size */

extern MAV_SMSCallback *mav_SMSCallback_size;
typedef int (*MAV_SMSCallbackSizeFn)(MAV_SMS *, int *);
void mav_SMSCallbackSizeSet(MAV_SMSClass *sc, MAV_SMSCallbackSizeFn fn);
int mav_SMSCallbackSizeExec(MAV_SMS *s, int *sz);

/* Contains object */

extern MAV_SMSCallback *mav_SMSCallback_objectContains;
typedef int (*MAV_SMSCallbackObjectContainsFn)(MAV_SMS *, MAV_object *, int *);
void mav_SMSCallbackObjectContainsSet(MAV_SMSClass *sc, MAV_SMSCallbackObjectContainsFn fn);
int mav_SMSCallbackObjectContainsExec(MAV_SMS *s, MAV_object *o, int *cnt);




/* Types of SMS */

/* object list type of SMS */

typedef struct {
  MAV_list *list;
} MAV_objList;

extern MAV_SMSClass *mav_SMSClass_objList;
int mav_objListObjectAdd(MAV_SMS *s, MAV_object *o);
int mav_objListObjectRmv(MAV_SMS *s, MAV_object *o);
int mav_objListIntersect(MAV_SMS *s, MAV_window *w, MAV_line *ln, MAV_objectIntersection *oi, MAV_object **o);
int mav_objListPointerReset(MAV_SMS *s);
int mav_objListPointerPush(MAV_SMS *s);
int mav_objListPointerPop(MAV_SMS *s);
int mav_objListObjectNext(MAV_SMS *s, MAV_object **o);
int mav_objListExecFn(MAV_SMS *s, MAV_drawInfo *di, MAV_SMSExecFn *fn);
int mav_objListEmpty(MAV_SMS *s, int *o);
int mav_objListDelete(MAV_SMS *s, int *o);
int mav_objListSize(MAV_SMS *s, int *sz);

MAV_objList *mav_objListNew(void);
MAV_SMS *mav_SMSObjListNew(void);

/* HBB type of SMS */

typedef struct MAVLIB_cluster {
  int status;
  MAV_BB box;
  float surface_area;
  int num_children;
  struct MAVLIB_cluster *parent;
  struct MAVLIB_child *children;
  MAV_object *obj;
} MAV_HBBCluster;

typedef struct MAVLIB_child {
  struct MAVLIB_cluster *child;
  struct MAVLIB_child *next;
} MAV_HBBChild;

typedef struct {
  MAV_HBBCluster *curr_cluster;
} MAV_HBBPointer;

typedef struct {
  MAV_HBBCluster *root;
  int size;
  MAV_HBBPointer *pointer;
} MAV_HBB;

extern MAV_SMSClass *mav_SMSClass_HBB;
int mav_HBBObjectAdd(MAV_SMS *s, MAV_object *o);
int mav_HBBObjectRmv(MAV_SMS *s, MAV_object *o);
int mav_HBBIntersect(MAV_SMS *s, MAV_window *w, MAV_line *ln, MAV_objectIntersection *oi, MAV_object **o);
int mav_HBBPointerReset(MAV_SMS *s);
int mav_HBBPointerPush(MAV_SMS *s);
int mav_HBBPointerPop(MAV_SMS *s);
int mav_HBBObjectNext(MAV_SMS *s, MAV_object **o);
int mav_HBBExecFn(MAV_SMS *s, MAV_drawInfo *di, MAV_SMSExecFn *fn);
int mav_HBBEmpty(MAV_SMS *s, int *o);
int mav_HBBDelete(MAV_SMS *s, int *o);
int mav_HBBSize(MAV_SMS *s, int *sz);

MAV_HBB *mav_HBBNew(void);
MAV_SMS *mav_SMSHBBNew(void);
void mav_HBBConstructFromSMS(MAV_SMS *target, MAV_SMS *from);



/* Supporting routines */

int mav_SMSDisplay(MAV_window *w, MAV_SMS *s);
int mav_SMSDisplayUsingDrawInfo(MAV_window *w, MAV_SMS *s, MAV_drawInfo di);
int mav_SMSDisplayUnCulled(MAV_window *w, MAV_SMS *s);
int mav_SMSIntersectLine(MAV_window *w, MAV_SMS *sms, MAV_line ln, MAV_objectIntersection *oi, MAV_object **o);
int mav_SMSIntersectLineAll(MAV_window *w, MAV_line ln, MAV_objectIntersection *oi, MAV_object **o);
int mav_SMSIntersectBB(MAV_window *w, MAV_SMS *sms, MAV_BB bb, MAV_SMS *objs);
int mav_SMSIntersectBBAll(MAV_window *w, MAV_BB bb, MAV_SMS *objs);



/* The hooks into SMS display */

extern MAV_SMSExecFnFn mav_SMS_displayFn;
void mav_SMSDisplayFn(MAV_object *, MAV_drawInfo *, void *);



/* Module initialisation */

char *mav_SMSModuleID(void);
int mav_SMSModuleInit(void);

#ifdef __cplusplus
}
#endif
#endif
