/* xrml.h */

#ifndef _XRML_H_
#define _XRML_H_

#ifdef __cplusplus
#include <iostream.h>
#include "error.H"
#include "Array.H"
#include "memory.H"

namespace xrml {

/* ***************************** simple types ***************************** */
// Only basic constructors and convertors to the nearest standard type are provided.
// Use builtin C++ types or your own vector .... classes (with appropriate 
// own type convertor) for computations.

class SFBool {
  bool val;
public:
  PoolDecl(SFBool, "SFBool")
  inline SFBool(const int b =false) 	{ val = b; }
  inline operator bool() const 		{ return val; }
  friend ostream& operator<<(ostream& s, const SFBool& v) { return s << (v.val ? "TRUE" : "FALSE"); }
  friend ostream& operator<<(ostream& s, const SFBool* v) { return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFString {
  char *val;
public:
  PoolDecl(SFString, "SFString")
  inline SFString(char *s ="") 		{ val = s; }
  inline operator char*() const		{ return val; }
  friend ostream& operator<<(ostream& s, const SFString& v) { return s << '"' << v.val << '"'; }
  friend ostream& operator<<(ostream& s, const SFString* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFInt32 {
  int val;
public:
  PoolDecl(SFInt32, "SFInt32")
  inline SFInt32(const int d =0) 	{ val = d; }
  inline operator int() const		{ return val; }
  friend ostream& operator<<(ostream& s, const SFInt32& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, const SFInt32* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFFloat {
  float val;
public:
  PoolDecl(SFFloat, "SFFloat")
  inline SFFloat(const float f =0.) 	{ val = f; }
  inline operator float() const		{ return val; }
  friend ostream& operator<<(ostream& s, const SFFloat& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, const SFFloat* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFTime {
  double val;
public:
  PoolDecl(SFTime, "SFTime")
  inline SFTime(const double f =-1.) 	{ val = f; }
  inline operator double() const	{ return val; }
  friend ostream& operator<<(ostream& s, const SFTime& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, const SFTime* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFVec2f {
  PoolDecl(SFVec2f, "SFVec2f")
  float s, t;
  inline SFVec2f(const float ss =0., const float tt =0.) { s = ss; t = tt; }
  friend ostream& operator<<(ostream& s, const SFVec2f& v) 	{ return s << v.s << ' ' << v.t; }
  friend ostream& operator<<(ostream& s, const SFVec2f* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFVec3f {
  PoolDecl(SFVec3f, "SFVec3f")
  float x, y, z;
  inline SFVec3f(const float xx =0., const float yy =0., const float zz =0.) { x=xx; y=yy; z=zz; }
  friend ostream& operator<<(ostream& s, const SFVec3f& v) 	{ return s << v.x << ' ' << v.y << ' ' << v.z; }
  friend ostream& operator<<(ostream& s, const SFVec3f* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFColor {
  PoolDecl(SFColor, "SFColor")
  float	r, g, b;
  inline SFColor(const float rr =0., const float gg =0., const float bb =0.) { r=rr; g=gg; b=bb; }
  friend ostream& operator<<(ostream& s, const SFColor& v) 	{ return s << v.r << ' ' << v.g << ' ' << v.b; }
  friend ostream& operator<<(ostream& s, const SFColor* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFRotation {
  PoolDecl(SFRotation, "SFRotation")
  float x, y, z, radians;
  inline SFRotation(const float xx =0., const float yy =0., const float zz =1., const float rad =0.) { x=xx; y=yy; z=zz, radians=rad; }
  friend ostream& operator<<(ostream& s, const SFRotation& v) 	{ return s << v.x << ' ' << v.y << ' ' << v.z << ' ' << v.radians; }
  friend ostream& operator<<(ostream& s, const SFRotation* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFImage {
  void construct(int w, int h, int n, unsigned int *pix);
  void destruct(void);

public:
  PoolDecl(SFImage, "SFImage")

  int width, height, num_components;
  unsigned int *pixels;

  SFImage(unsigned int w =0, unsigned int h =0, unsigned int n =0, unsigned int *pix =0);
  SFImage(const SFImage& src);
  SFImage& operator=(const SFImage& src);
  ~SFImage();

  friend ostream& operator<<(ostream&, SFImage&);
  friend ostream& operator<<(ostream& s, SFImage* im) { return im ? operator<<(s, *im) : (s << "NULLL"); }
};

/* ****************************** SFNode class **************************** */
extern bool IsSFNode(class SFNode*);

typedef union { int i; void *p; } client_data;
extern void clear(client_data& data);

class SFNode: public PooledObj {
  friend class interfaceMember;
  friend class interfaceMemberRef;
  friend class link;
  friend class route;
  friend class field;
  friend class Proto;
  friend class ExternProto;
  friend class world;

public:
  int refCount;			// reference count
  int nameIndex;		// index of DEF'ed node in namedNodes table or -1
  int nrInterfaceMembers;		// nr of node interface members
  class interfaceMember** interface;	// pointers to interface members (see nodeInterface.H)

  // special client data for exporters and importers
  client_data import_data, export_data;

  // constructors and destructor
  SFNode(const char *id =0, int nrInterfaceMemebrs =0, class interfaceMember** interface =0);
  SFNode(const SFNode& src);
  SFNode& operator=(const SFNode& src);
  virtual ~SFNode();

protected:
  virtual void construct(const char *id =0, int nrInterfaceMembers =0, class interfaceMember** interface =0);
  virtual void clone(const SFNode& src);
  virtual void destruct(void);

  virtual void clone_interface(const SFNode& src);
  virtual void instantiate_interface(class Proto *enclosing_proto =0);

  // Complains about mistakenly calling base class virtual member
  // functions, due to explicitly casting a node to a base class e.g.
  virtual void stub(const char* membername) const;

  // Flags for keeping track of node state updates. For built-in nodes,
  // each bit corresponds uniqeuly with a field, exposedField, or eventOut
  // in the nodes interface. Use member function "xxx_is_updated()" to
  // inspect whether a member has changed, and "xxx_clear_update()"
  // to clear the flag for field/exposedField/eventOUt "xxx".
  // The flags are raised in assign_xxx() and post_xxx() member functions
  // of leaf node classes.
  // NOTE: On most platforms, an unsigned int contains 32 bits, so that
  // there is room for 32 fields and eventOuts in built-in nodes. If this
  // is not enough, change the type of status to 'long long unsigned'.
  // There is no one-to-one correspondence between bits in 'status' and
  // interface members of PROTO nodes, so that PROTO's don't suffer this
  // 32-members limitation.
  unsigned status;

public:
  //
  virtual int major_version(void), minor_version(void);
  virtual bool is_leaf_class(void);

  //
  const char *typeId;			// typeId of the node.
  const char *nameId;			// nameId is name of DEF'ed node or 0

  // filename and lineno when the node was created.
  char *filename;
  int line;

  // time of last node state update.
  double timestamp;

  // user data.
  client_data data;

  // World the node belongs to (for current time, event queue, etc...)
  // See World.H.
  class world* world;

  // Composes a unique name identifying the node, for debugging etc...
  virtual char* name(char* buf =0) const;

  // Checks whether node state has changed since last "clear_update()"
  inline bool is_updated(void) const { return status!=0; }

  // Clears update status for all fields and eventOuts of the node.
  inline void clear_update(void) { status = 0; }

  // Returns the interface Member with given Id or 0 if there is no such 
  // interface member
  class interfaceMember* get(const char *Id);

  // Returns a pointer to the first node of nodes scene graph. The first node
  // is the node itself if it is a builtin node and the first node of the PROTO
  // scene graph if it is a PROTO node (see Proto.H). Used for PROTO node resolution,
  // among other things used to determine whether or not a node is of the correct type
  // for an assignment (e.g. Appaerance node for Shape.appearance etc...).
  virtual SFNode *firstnode(void) { return this; }

  // Creates and returns an instance of 'this', basically a copy of 'this'
  // with it's own interface and field/event redirections resolved to
  // the interface of the Proto node that is passed (if one is passed)
  // as an argument. 'enclosing_proto' shall be the innermost PROTO node
  // enclosing the node to be instantiated.
  virtual SFNode* instantiate(class Proto *enclosing_proto =0);

  // The actual rendering of a node is accomplished by renderer class methods
  // (see renderer.H). This node class method will call the appropriate renderer
  // method(s) for the node and traverse children node graphs. This node
  // class method should be called for every root node in the world in order to
  // render a frame.
  virtual void render(void);

  // Prints the nodes contents. For debugging etc... (overloadable function)
  virtual ostream& print(ostream& s =cout);

  friend ostream& operator<<(ostream& s, SFNode& v) { return v.print(s); }
  friend ostream& operator<<(ostream& s, SFNode* v) { return v ? operator<<(s,*v) : (s << "NULL"); }
};

/* ************************** array types ************************** */
class MFBool: public array<SFBool> {
public:
  PoolDecl(MFBool, "MFBool")

  inline MFBool() { init(0,0); }
  inline MFBool(int len, SFBool *table =0) { init(len, table); }

  // these members should be inherited from array, but
  // gcc enforces us to explictly declare them here too.
  friend ostream& operator<<(ostream& s, const MFBool& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFBool *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFString: public array<SFString> {
public:
  PoolDecl(MFString, "MFString")

  inline MFString() { init(0,0); }
  inline MFString(int len, SFString *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFString& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFString *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFInt32: public array<SFInt32> {
public:
  PoolDecl(MFInt32, "MFInt32")

  inline MFInt32() { init(0,0); }
  inline MFInt32(int len, SFInt32 *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFInt32& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFInt32 *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFFloat: public array<SFFloat> {
public:
  PoolDecl(MFFloat, "MFFloat")

  inline MFFloat() { init(0,0); }
  inline MFFloat(int len, SFFloat *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFFloat& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFFloat *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFTime: public array<SFTime> {
public:
  PoolDecl(MFTime, "MFTime")

  inline MFTime() { init(0,0); }
  inline MFTime(int len, SFTime *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFTime& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFTime *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFVec2f: public array<SFVec2f> {
public:
  PoolDecl(MFVec2f, "MFVec2f")

  inline MFVec2f() { init(0,0); }
  inline MFVec2f(int len, SFVec2f *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFVec2f& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFVec2f *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFVec3f: public array<SFVec3f> {
public:
  PoolDecl(MFVec3f, "MFVec3f")

  inline MFVec3f() { init(0,0); }
  inline MFVec3f(int len, SFVec3f *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFVec3f& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFVec3f *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFColor: public array<SFColor> {
public:
  PoolDecl(MFColor, "MFColor")

  inline MFColor() { init(0,0); }
  inline MFColor(int len, SFColor *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFColor& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFColor *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFRotation: public array<SFRotation> {
public:
  PoolDecl(MFRotation, "MFRotation")

  inline MFRotation() { init(0,0); }
  inline MFRotation(int len, SFRotation *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFRotation& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFRotation *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

class MFImage: public array<SFImage> {
public:
  PoolDecl(MFImage, "MFImage")

  inline MFImage() { init(0,0); }
  inline MFImage(int len, SFImage *table =0) { init(len, table); }

  friend ostream& operator<<(ostream& s, const MFImage& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFImage *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

// MFNode contains pointers to SFNode's, not the SFNode objects itself.
class MFNode: public array<SFNode*> {
public:
  PoolDecl(MFNode, "MFNode")

  inline MFNode() { init(0,0); }
  inline MFNode(int len, SFNode **table =0) { init(len, table); }

  // Returns a new MFNode with instances of the contained SFNodes
  MFNode *instantiate(class Proto *enclosing_proto =0);

  // Calls SFNode::render() for every node in the MFNode.
  void render(void);

  friend ostream& operator<<(ostream& s, const MFNode& ar) { return ar.print(s); }
  friend ostream& operator<<(ostream& s, MFNode *ar) { return ar ? ar->print(s) : (s << "NULL"); }
};

} // namespace xrml

#else /* __cplusplus */
/* opaque types in plain C code */

#define SFBool		void
#define SFString	void
#define SFInt32		void
#define SFFloat		void
#define SFTime		void
#define SFVec2f		void
#define SFVec3f		void
#define SFColor		void
#define SFRotation	void
#define SFImage		void
#define SFNode		void

#define MFBool		void
#define MFString	void
#define MFInt32		void
#define MFFloat		void
#define MFTime		void
#define MFVec2f		void
#define MFVec3f		void
#define MFColor		void
#define MFRotation	void
#define MFImage		void
#define MFNode		void

#define world	void

#endif /*__cplusplus*/

#endif /*_XRML_H_*/

