/****************************************************************************/
/*  xmCi2.h - CommonInteract II header file - (09/23/1992) 02/18/1993       */
/****************************************************************************/
/*                                                                          */
/*   Copyright (c) 1991, 1992, 1993  Bernhard Strassl                       */
/*       Vienna User Interface Group                                        */
/*       Institute for Applied Computer Science and Information Systems     */
/*       University of Vienna, Austria                                      */
/*                                                                          */
/*   See file COPYRIGHT in this directory for details. If this file is      */
/*   missing please mail to xmpp@ani.univie.ac.at                           */
/****************************************************************************/

#ifndef XmCi2_included
#define XmCi2_included 1

#include "xmDrawing.h"

#ifndef CI_OVERRIDE_DEFAULTS
#define CI_MAX_CHILDREN 50
#define CI_MAX_TREE_SIZE 500
#define CI_MAX_ASSIGNINFO_NAMES 30
#define CI_MAX_METHODS 10
#endif

#define CI_DEFAULT_NAME "unnamedObject"

#define CI_NUM_INTERACTION_PRIMITIVES 8

typedef enum ciPrim { Mark, Move, Assign, Resize, Select, Activate, ChangeContents, ChangeData };

typedef unsigned int ciAttrib;

#define MARKABLE		SELECT
#define MOVEABLE		MOVE
#define RESIZEABLE		RESIZE_ANY
#define SELECTABLE		0x0400
#define ACTIVATEABLE	0x0800
#define CHANGEABLE		0x0A00

#define CI_DEFAULT_ATTRIBUTES MARKABLE | MOVEABLE | RESIZEABLE

// Note: ASSIGN is controlled by the application through the allowAssign...() members!

typedef short ciState;

#define NORMAL			0x00
#define MARKED			SELECTED
#define PRIMARY_MARKED	PRIMARY_SELECTION
#define DISABLED		0x04

struct ciCallbackInfo
{
	bool isXmCallback;
	XmRootClass* receiver;
	cbProc callback;
	void* clientData;

	ciCallbackInfo(XmRootClass* ob, cbProc cbk, void* cd)	{ isXmCallback = FALSE; receiver = ob; callback = cbk; clientData = cd; }
};

struct ciMethod
{
	char* msgName;
	char* paramType;
	cbProc callback;

	ciMethod(char* n, char* pt, cbProc p)	{ msgName = strcpy(new char[strlen(n) + 1], n); paramType = pt ? strcpy(new char[strlen(pt) + 1], pt) : pt; callback = p; }
	~ciMethod()								{ if(msgName) delete msgName; if(paramType) delete paramType; }

	bool match(char* n, char* pt)			{ return(n ? ((!strcmp(n, msgName) && (pt ? !strcmp(pt, paramType) : pt == paramType)) ? TRUE : FALSE) : FALSE); }
};

#define CB_CI_DATA CB_XM_DATA
#define CB_CLASS_NAME ((void* )10L)

struct ciClientData
{
	bool* answer;
	void* clientData;
	int x, y;
	CiObject* obj;
	int operation;

	ciClientData(bool& a, void* cd, int nx, int ny, CiObject* ob, int op)	{ answer = &a; clientData = cd; x =nx; y = ny; obj = ob; operation = op; }

	CiObject* clientObject()	{ return((CiObject* )clientData); }
};

#define OP_ADD 1
#define OP_REMOVE 2

#define PARENT_CLASSES	0
#define PARENT_OBJECTS	1
#define CHILD_CLASSES	2
#define CHILD_OBJECTS	3

// getChildren search codes
#define CH_THIS 0		// only direct children of the receiver
#define CH_SHALLOW 1	// the root of each subhierarchy matching a given status
#define CH_ALL 2		// all children in any depth

struct assignInfo
{
	char* names[CI_MAX_ASSIGNINFO_NAMES][4];
	int nums[4];

	assignInfo()	{ nums[0] = nums[1] = nums[2] = nums[3] = 0; }
};

class CiObject : public DrawPrim
{
friend class XmCiWorld;
	XmRootClass* basePtr;
	XmCiWorld* world;
	CiObject* parent;
	CiObject* children[CI_MAX_CHILDREN];
	XmControl* control;
	int numChildren;
	gprPoint relCoord;
	ciAttrib attributes;
	ciState state;
	ciCallbackInfo* preOpCallbacks[CI_NUM_INTERACTION_PRIMITIVES];
	ciCallbackInfo* postOpCallbacks[CI_NUM_INTERACTION_PRIMITIVES];
	assignInfo assigninf;
	CiObject* reAssigned;
	bool moved;
	void* objData;
	char* instName;
	ciMethod* protocol[CI_MAX_METHODS];
	int methodCount;
public:
	virtual char* className()	{ return("ObjectClass"); }
private:
	void initObject(char*, ciAttrib);
	bool callCallback(ciPrim, bool, int = 0, int = 0, CiObject* = NULL, int = 0);
	void changeAssignInfo(bool, int, char*);
	bool matchAssignInfo(int, char*);

	bool objMark(bool, bool, bool = FALSE, bool = FALSE, bool = TRUE);
	bool objAssign(CiObject*, int, int, bool, bool = FALSE, bool = FALSE, bool = FALSE);
	bool objResize(int, int, bool, bool = FALSE, bool = FALSE, bool = FALSE);
	void objSelect(int, int);
	void objActivate();
	bool objChangeData(void*, bool, bool = FALSE, bool = FALSE);

	void addTreeTo(XmCiWorld*);
	void removeTreeFrom(XmCiWorld*);
	void markChildren(bool);
	void relocateChildren(int, int);
	void restackChild(CiObject*, bool = TRUE);
	CiObject* getMarkedRoot();
protected:
	int findMethod(char*, char*);
	bool registerMethod(char*, cbProc, char* = NULL);
	gprData* getData()		{ return(data); }
public:
	CiObject(DrawPrim*, char* = CI_DEFAULT_NAME, ciAttrib = CI_DEFAULT_ATTRIBUTES);
	CiObject(XmControl*, char* = CI_DEFAULT_NAME, ciAttrib = CI_DEFAULT_ATTRIBUTES);
	virtual ~CiObject();

	CiObject* addChild(CiObject*, bool = TRUE);
	CiObject* removeChild(CiObject*, bool = FALSE);
	CiObject* child(int i)	{ return((i >= 0 && i < numChildren) ? children[i] : NULL); }
	int childrenCount()		{ return(numChildren); }

	CiObject** getChildren(int code = CH_THIS, ciState = -1, CiObject** = NULL, int* = NULL);

	CiObject* linkTo(CiObject*);
	CiObject* linkTo(XmCiWorld*);
	CiObject* unlink();
	
	void changeName(char* aName)				{ delete instName; instName = strcpy(new char[strlen(aName) + 1], aName); }
	CiObject* setInitialOrigin(int x, int y)	{ relCoord.x = x; relCoord.y = y; return(this); }
	bool setAttributes(ciAttrib, bool);

	bool setCallback(ciPrim, CiObject*, cbProc, bool = TRUE, bool = FALSE, void* = CB_OBJ_PTR);
	bool setCallback(ciPrim, XmObject*, cbProc, bool = TRUE, bool = FALSE, void* = CB_OBJ_PTR);

	bool disable();
	bool enable();

	bool mark(bool notify = FALSE)									{ return(objMark(TRUE, notify)); }
	bool unmark(bool notify = FALSE)								{ return(objMark(FALSE, notify)); }
	bool move(int nx, int ny, bool notify = FALSE)					{ return(objAssign(parent, nx, ny, notify)); }
	bool assign(CiObject* rec, int x, int y, bool notify = FALSE)	{ return(objAssign(rec, x, y, notify)); }
	bool resize(int nw, int nh, bool notify = FALSE)				{ return(objResize(nw, nh, notify)); }
	bool changeData(void* d, bool notify = FALSE)					{ return(objChangeData(d, notify)); }

	char* getName()						{ return(instName); }
	char* getClassName()				{ return(className()); }
	bool isA(char* n)					{ return(strcmp(className(), n) ? FALSE : TRUE); }
	CiObject* getParent()				{ return(parent); }
	XmCiWorld* getWorld();
	bool wasAssigned()					{ return(reAssigned ? TRUE : FALSE); }
	bool wasMoved()						{ return(moved); }

	gprPoint calcRel(gprPoint);
	gprPoint relOrigin()				{ return(calcRel(origin())); }
	gprPoint relCorner()				{ return(calcRel(corner())); }
	gprPoint relCenter()				{ return(calcRel(center())); }

	bool getState(ciState);
	void makeRelative(int&, int&);
	void makeAbsolute(int&, int&);

	void toForeground(bool = TRUE);
	void toBackground(bool = TRUE);

	void allowAssignmentOf(char*, ...);
	void denyAssignmentOf(char*, ...);
	void allowAssigningTo(char*, ...);
	void denyAssigningTo(char*, ...);

	bool validateParent(CiObject* anObj)	{ return((bool )(anObj ? (matchAssignInfo(PARENT_CLASSES, anObj->className()) || matchAssignInfo(PARENT_OBJECTS, anObj->instName)) : matchAssignInfo(PARENT_OBJECTS, "WORLD"))); }
	bool validateChild(CiObject* anObj)		{ return((bool )(matchAssignInfo(CHILD_CLASSES, anObj->className()) || matchAssignInfo(CHILD_OBJECTS, anObj->instName))); }

	bool msg(char*, char* = NULL, void* = NULL);
};

class XmCiWorld : public XmDrawing
{
	CiObject* children[CI_MAX_CHILDREN];
	int numChildren;
friend void CiObject::toForeground(bool);
friend void CiObject::toBackground(bool);
	void restackChild(CiObject*, bool = TRUE);
public:
	XmCiWorld(char*, int = 0, int = 0, int = 0, int = 0);
	~XmCiWorld();

	CiObject* addChild(CiObject*);
	CiObject* removeChild(CiObject*);
	CiObject* child(int i)	{ return((i >= 0 && i < numChildren) ? children[i] : NULL); }
	int childrenCount()		{ return(numChildren); }

	CiObject** getChildren(int code = CH_THIS, ciState = -1, CiObject** = NULL, int* = NULL);

	bool userClick(int, int);
	bool userSelect(DrawPrim*, int, int);
	bool userMove(DrawPrim*, int, int, int, int);
	bool userResize(DrawPrim*, int, int);
	void userActivate(DrawPrim*, int, int);
	bool userDragEnter(DrawPrim*, DrawPrim**, bool*);
};

/*

class OwObject : public CiObject
{
	OwObject** presentations;
	int numPres;
};

*/

#endif
