/*
 * Node.h
 *
 * Copyright (C) 1999 Stephen F. White, 2005 J. "MUFTI" Scheurich
 * 
 * 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 (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#ifndef _NODE_H
#define _NODE_H

#ifndef _STDIO_H
#include <stdio.h>
#endif

#ifndef _ARRAY_H
#include "Array.h"
#endif

#ifndef _LIST_H
#include "List.h"
#endif

#ifndef _VEC3F_H
#include "Vec3f.h"
#endif

#ifndef _DUNE_STRING_H
#include "MyString.h"
#endif

#ifndef _FIELD_INDEX_H
#include "FieldIndex.h"
#endif
#ifndef _ELEMENT_H
#include "Element.h"
#endif

#include "Swap.h"
#include "MeshFlags.h"
#include "ac3dMaterialCallback.h"

class FieldValue;
class Node;
class Scene;
//class Proto;
class NodePROTO;
class Path;
class NodeList;

class RouteSocket {
public:
                RouteSocket() 
                   { 
                   _node = NULL; 
                   _field = -1; 
                   }
                RouteSocket(Node *node, int index) 
                   { 
                   _node = node; 
                   _field = index; 
                   }

    int         operator==(const RouteSocket &t)
                   { return t._node == _node && t._field == _field; }
 
    int         operator!=(const RouteSocket &t)
                   { return t._node != _node || t._field != _field; }

    Node       *getNode(void) const { return _node; }
    int         getField(void) const { return _field; }
protected:
    Node       *_node;
    int         _field;
};

typedef List<RouteSocket> SocketList;

enum parentFlag {
    PARENT_NOT_TOUCHED,
    PARENT_TOUCHED,
    PARENT_RECURSIVE
};

class Parent {
public:
                Parent() 
                   { 
                   _node = NULL; 
                   _field = -1;
                   _self = NULL; 
                   _parentFlag = PARENT_NOT_TOUCHED;
                   }
  
                Parent(Node *node, int field, Node *self) 
                   { 
                   _node = node; 
                   _field = field;
                   _self = self; 
                   _parentFlag = PARENT_NOT_TOUCHED;
                   }

    int         operator==(const Parent &t)
                   { return t._self == _self; }

    int         operator!=(const Parent &t)
                   { return t._self != _self; }

    Node       *_node;
    int         _field;
    Node       *_self;
    parentFlag  _parentFlag;             
};

typedef Array<Parent> ParentArray;

enum flags {
    NODE_FLAG_TOUCHED,
    NODE_FLAG_COLLAPSED,
    NODE_FLAG_DEFED,
    NODE_FLAG_CONVERTED,
    NODE_FLAG_FLIPPED,
    NODE_FLAG_SWAPPED
};

enum Constraint {
    CONSTRAIN_NONE = 0,
    CONSTRAIN_X,
    CONSTRAIN_Y,
    CONSTRAIN_Z,
    CONSTRAIN_XY,
    CONSTRAIN_YZ,
    CONSTRAIN_ZX,
    CONSTRAIN_SPHERE
};


// X3D_NODE_TYPE
enum NodeEnum {
    VRML_ANCHOR,
    VRML_APPEARANCE,
    X3D_ARC_2D,
    X3D_ARC_CLOSE_2D,
    COVER_AR_SENSOR,
    VRML_AUDIO_CLIP,
    VRML_BACKGROUND,
    X3D_BALL_JOINT,
    VRML_BILLBOARD,
    KAMBI_BLEND_MODE,
    X3D_BOOLEAN_FILTER,
    X3D_BOOLEAN_TOGGLE,
    X3D_BOOLEAN_TRIGGER,
    X3D_BOOLEAN_SEQUENCER,
    X3D_BOUNDED_PHYSICS_MODEL,
    VRML_BOX,
    X3D_CAD_ASSEMBLY,
    X3D_CAD_FACE,
    X3D_CAD_LAYER,
    X3D_CAD_PART,
    DUNE_CATT_EXPORT_REC, // Export data container node for CATT 8 file format
    DUNE_CATT_EXPORT_SRC, // Export data container node for CATT 8 file format
    X3D_CIRCLE_2D,
    X3D_CLIP_PLANE,
    X3D_COLLIDABLE_OFFSET,
    X3D_COLLIDABLE_SHAPE,
    VRML_COLLISION,
    X3D_COLLISION_COLLECTION,
    X3D_COLLISION_SENSOR,
    X3D_COLLISION_SPACE,
    VRML_COLOR,
    X3D_COLOR_DAMPER,
    VRML_COLOR_INTERPOLATOR,
    X3D_COLOR_RGBA,
    X3D_COMPOSED_CUBE_MAP_TEXTURE,
    X3D_COMPOSED_SHADER,
    X3D_COMPOSED_TEXTURE_3D,
    VRML_CONE,
    X3D_CONE_EMITTER,
    X3D_CONTACT,
    VRML_CONTOUR_2D,
    VRML_CONTOUR_POLYLINE_2D,
    VRML_COORDINATE,
    X3D_COORDINATE_DAMPER,
    VRML_COORDINATE_DEFORMER,
    X3D_COORDINATE_DOUBLE,
    VRML_COORDINATE_INTERPOLATOR,
    X3D_COORDINATE_INTERPOLATOR_2D,
    COVER_COVER,
    COVER_CUBE_TEXTURE,
    VRML_CYLINDER,
    VRML_CYLINDER_SENSOR,
    VRML_DIRECTIONAL_LIGHT,
    X3D_DIS_ENTITY_MANAGER,
    X3D_DIS_ENTITY_TYPE_MAPPING,
    X3D_DISK_2D,
    X3D_DOUBLE_AXIS_HINGE_JOINT,
    X3D_EASE_IN_EASE_OUT,
    VRML_ELEVATION_GRID,
    X3D_ESPDU_TRANSFORM,
    X3D_EXPLOSION_EMITTER,
    VRML_EXTRUSION,
    X3D_FILL_PROPERTIES,
    X3D_FLOAT_VERTEX_ATTRIBUTE,
    VRML_FOG,
    X3D_FOG_COORDINATE,
    VRML_FONT_STYLE,
    X3D_FORCE_PHYSICS_MODEL,
    X3D_GENERATED_CUBE_MAP_TEXTURE,
    KAMBI_GENERATED_SHADOW_MAP,
    VRML_GEO_COORDINATE,
    VRML_GEO_ELEVATION_GRID,
    VRML_GEO_LOCATION,
    VRML_GEO_LOD,
    X3D_GEO_METADATA,
    VRML_GEO_ORIGIN,
    VRML_GEO_POSITION_INTERPOLATOR,
    X3D_GEO_PROXIMITY_SENSOR,
    VRML_GEO_TOUCH_SENSOR,
    X3D_GEO_TRANSFORM,
    VRML_GEO_VIEWPOINT,
    X3D_GRAVITY_PHYSICS_MODEL,
    VRML_GROUP,
    X3D_HANIM_DISPLACER,
    X3D_HANIM_HUMANOID,
    X3D_HANIM_JOINT,
    X3D_HANIM_SEGMENT,
    X3D_HANIM_SITE,
    X3D_IMAGE_CUBE_MAP_TEXTURE,
    VRML_IMAGE_TEXTURE,
    X3D_IMAGE_TEXTURE_3D,
    VRML_INDEXED_FACE_SET,
    VRML_INDEXED_LINE_SET,
    X3D_INDEXED_QUAD_SET,
    X3D_INDEXED_TRIANGLE_FAN_SET,
    X3D_INDEXED_TRIANGLE_SET,
    X3D_INDEXED_TRIANGLE_STRIP_SET,
    VRML_INLINE,
    VRML_INLINE_LOAD_CONTROL,
    X3D_INTEGER_SEQUENCER,
    X3D_INTEGER_TRIGGER,
    COVER_JOYSTICK_SENSOR,
    KAMBI_KAMBI_APPEARANCE,
    KAMBI_KAMBI_HEAD_LIGHT,
    KAMBI_KAMBI_INLINE,
    KAMBI_KAMBI_NAVIGATION_INFO,
    KAMBI_KAMBI_OCTREE_PROPERTIES,
    KAMBI_KAMBI_TRIANGULATION,
    X3D_KEY_SENSOR,
    COVER_LAB_VIEW,
    X3D_LAYER,
    X3D_LAYER_SET,
    X3D_LAYOUT,
    X3D_LAYOUT_GROUP,
    X3D_LAYOUT_LAYER,
    DUNE_LDRAW_DAT_EXPORT, // Export data container node for ldraw.dat file format
    X3D_LINE_PICK_SENSOR,
    X3D_LINE_PROPERTIES,
    X3D_LINE_SET,
    X3D_LOAD_SENSOR,
    X3D_LOCAL_FOG,
    VRML_LOD,
    VRML_MATERIAL,
    X3D_MATRIX_3_VERTEX_ATTRIBUTE,
    X3D_MATRIX_4_VERTEX_ATTRIBUTE,
    KAMBI_MATRIX_TRANSFORM,
    X3D_METADATA_DOUBLE,
    X3D_METADATA_FLOAT,
    X3D_METADATA_INTEGER,
    X3D_METADATA_SET,
    X3D_METADATA_STRING,
    X3D_MOTOR_JOINT,
    VRML_MOVIE_TEXTURE,
    KAMBI_MULTI_GENERATED_TEXTURE_COORDINATE,
    X3D_MULTI_TEXTURE,
    X3D_MULTI_TEXTURE_COORDINATE,
    X3D_MULTI_TEXTURE_TRANSFORM,
    VRML_NAVIGATION_INFO,
    VRML_NORMAL,
    VRML_NORMAL_INTERPOLATOR,
    VRML_NURBS_CURVE,
    VRML_NURBS_CURVE_2D,
    VRML_NURBS_GROUP,
    X3D_NURBS_ORIENTATION_INTERPOLATOR,
    VRML_NURBS_POSITION_INTERPOLATOR,
    X3D_NURBS_SET,
    VRML_NURBS_SURFACE,
    X3D_NURBS_SURFACE_INTERPOLATOR,
    X3D_NURBS_SWEPT_SURFACE,
    X3D_NURBS_SWUNG_SURFACE,
    X3D_NURBS_TEXTURE_COORDINATE,
    VRML_NURBS_TEXTURE_SURFACE,
    X3D_NURBS_TRIMMED_SURFACE,
    DUNE_ODE_MOTOR_JOINT,
    DUNE_ODE_SINGLE_AXIS_HINGE_JOINT,
    DUNE_ODE_SLIDER_JOINT,
    X3D_ORIENTATION_CHASER,
    X3D_ORIENTATION_DAMPER,
    VRML_ORIENTATION_INTERPOLATOR,
    X3D_ORTHO_VIEWPOINT,
    X3D_PACKAGED_SHADER,
    X3D_PARTICLE_SYSTEM,
    X3D_PICKABLE_GROUP,
    VRML_PIXEL_TEXTURE,
    X3D_PIXEL_TEXTURE_3D,
    VRML_PLANE_SENSOR,
    X3D_POINT_EMITTER,
    VRML_POINT_LIGHT,
    X3D_POINT_PICK_SENSOR,
    VRML_POINT_SET,
    X3D_POLYLINE_2D,
    X3D_POLYLINE_EMITTER,
    X3D_POLYPOINT_2D,
    X3D_POSITION_CHASER_2D,
    X3D_POSITION_CHASER,
    X3D_POSITION_DAMPER_2D,
    X3D_POSITION_DAMPER,
    VRML_POSITION_INTERPOLATOR,
    X3D_POSITION_INTERPOLATOR_2D,
    X3D_PRIMITIVE_PICK_SENSOR,
    X3D_PROGRAM_SHADER,
    KAMBI_PROJECTED_TEXTURE_COORDINATE,
    VRML_PROXIMITY_SENSOR,
    X3D_QUAD_SET,
    X3D_RECEIVER_PDU,
    X3D_RECTANGLE_2D,
    KAMBI_RENDERED_TEXTURE,
    X3D_RIGID_BODY,
    X3D_RIGID_BODY_COLLECTION,
    X3D_SCALAR_CHASER,
    VRML_SCALAR_INTERPOLATOR,
    X3D_SCREEN_FONT_STYLE,
    X3D_SCREEN_GROUP,
    VRML_SCRIPT,
    X3D_SHADER_PART,
    X3D_SHADER_PROGRAM,
    VRML_SHAPE,
    X3D_SIGNAL_PDU,
    X3D_SINGLE_AXIS_HINGE_JOINT,
    COVER_SKY,
    X3D_SLIDER_JOINT,
    VRML_SOUND,
    COVER_SPACE_SENSOR,
    VRML_SPHERE,
    VRML_SPHERE_SENSOR,
    X3D_SPLINE_POSITION_INTERPOLATOR,
    X3D_SPLINE_POSITION_INTERPOLATOR_2D,
    X3D_SPLINE_SCALAR_INTERPOLATOR,
    VRML_SPOT_LIGHT,
    X3D_SQUAD_ORIENTATION_INTERPOLATOR,
    X3D_STATIC_GROUP,
    X3D_STRING_SENSOR,
    COVER_STEERING_WHEEL,
    DUNE_SUPER_ELLIPSOID,
    DUNE_SUPER_EXTRUSION,
    DUNE_SUPER_REVOLVER,
    DUNE_SUPER_SHAPE,
    X3D_SURFACE_EMITTER,
    VRML_SWITCH,
    KAMBI_TEAPOT,
    X3D_TEX_COORD_DAMPER,
    X3D_TEX_COORD_DAMPER_2D,
    VRML_TEXT,
    KAMBI_TEXT_3D,
    X3D_TEXTURE_BACKGROUND,
    VRML_TEXTURE_COORDINATE,
    X3D_TEXTURE_COORDINATE_3D,
    X3D_TEXTURE_COORDINATE_4D,
    X3D_TEXTURE_COORDINATE_GENERATOR,
    X3D_TEXTURE_PROPERTIES,
    VRML_TEXTURE_TRANSFORM,
    X3D_TEXTURE_TRANSFORM_3D,
    X3D_TEXTURE_TRANSFORM_MATRIX_3D,
    VRML_TIME_SENSOR,
    X3D_TIME_TRIGGER,
    VRML_TOUCH_SENSOR,
    VRML_TRANSFORM,
    X3D_TRANSFORM_SENSOR,
    X3D_TRANSMITTER_PDU,
    X3D_TRIANGLE_FAN_SET,
    X3D_TRIANGLE_SET,
    X3D_TRIANGLE_SET_2D,
    X3D_TRIANGLE_STRIP_SET,
    VRML_TRIMMED_SURFACE,
    COVER_TUI_BUTTON,
    COVER_TUI_COMBO_BOX,
    COVER_TUI_FLOAT_SLIDER,
    COVER_TUI_FRAME,
    COVER_TUI_LABEL,
    COVER_TUI_LIST_BOX,
    COVER_TUI_MAP,
    COVER_TUI_PROGRESS_BAR,
    COVER_TUI_SLIDER,
    COVER_TUI_SPLITTER,
    COVER_TUI_TAB,
    COVER_TUI_TAB_FOLDER,
    COVER_TUI_TOGGLE_BUTTON,
    X3D_TWO_SIDED_MATERIAL,
    X3D_UNIVERSAL_JOINT,
    COVER_VEHICLE,
    VRML_VIEWPOINT,
    X3D_VIEWPOINT_GROUP,
    X3D_VIEWPORT,
    COVER_VIRTUAL_ACOUSTICS,
    COVER_VIRTUAL_SOUND_SOURCE,
    VRML_VISIBILITY_SENSOR,
    X3D_VOLUME_EMITTER,
    X3D_VOLUME_PICK_SENSOR,
    DUNE_VRML_CUT,
    DUNE_VRML_SCENE,
    COVER_WAVE,
    X3D_WIND_PHYSICS_MODEL,
    VRML_WORLD_INFO,

    // fake nodes
    VRML_COMMENT,
    X3D_EXPORT,
    X3D_IMPORT,

    // the following are node "classes", used to validate the
    // scene graph hierarchy

    ANY_NODE,
    AUDIO_CLIP_NODE,
    BODY_COLLIDABLE_NODE,
    BODY_COLLISION_SPACE_NODE,
    COORDINATE_NODE,
    COLOR_NODE,
    FONT_STYLE_NODE,
    HANIM_CHILD_NODE,
    INLINE_NODE,
    INTERPOLATOR_NODE,
    MATERIAL_NODE,
    METADATA_NODE,
    MOVIE_TEXTURE_NODE,
    NURBS_CONTROL_CURVE_NODE,
    NURBS_TEXTURE_COORDINATE_NODE,
    LAYER_NODE,
    LIGHT_NODE,
    LINE_SET_NODE,
    LOD_NODE,
    PARAMETRIC_GEOMETRY_NODE,
    PARTICLE_EMITTER_NODE,
    PARTICLE_PHYSICS_MODEL_NODE,
    PRODUCT_STRUCTURE_CHILD_NODE,
    PRIMITIVE_GEOMETRY_NODE,
    RIGID_JOINT_NODE,
    ROOT_NODE, // still a dummy
    SHAPE_NODE,
    SHADER_NODE,
    VERTEX_ATTRIBUTE_NODE,
    VIEWPOINT_NODE,
    VIEWPOINT_GROUP_NODE,

    // combined types
    AUDIO_CLIP_OR_MOVIE_TEXTURE_NODE,
    BODY_COLLIDABLE_OR_BODY_COLLISION_SPACE_NODE,
    GENERATED_TEXTURE_COORDINATE_NODE,
    NURBS_TEXTURE_COORDINATE_OR_TEXTURE_COORDINATE_NODE,
    PRIMITIVE_GEOMETRY_OR_MASS_DENSITY_MODEL_NODE,
    SHAPE_OR_INLINE_NODE,
    SHAPE_OR_LOD_NODE,
    SPOTLIGHT_OR_DIRECTIONALLIGHT_OR_VIEWPOINT_NODE,
    VIEWPOINT_OR_VIEWPOINT_GROUP_NODE,

    // the nodeclass of the following types can be bitwise OR'ed to any node
    NOT_SELF_NODE           = 1 << 21,
    TEXTURE_COORDINATE_NODE = 1 << 22,
    TEXTURE_TRANSFORM_NODE  = 1 << 23,
    TEXTURE_NODE            = 1 << 24,
    TEXTURE_2D_NODE         = 1 << 25,
    GEOMETRY_NODE           = 1 << 26,
    CHILD_NODE              = 1 << 27,
    GROUPING_NODE           = 1 << 28,
    URL_NODE                = 1 << 29,
    PROTO_NODE              = 1 << 30 
    // do not use bit 31 (sign bit)
};

#define LAST_NODE VRML_COMMENT

enum {
    PROFILE_CORE,
    PROFILE_INTERCHANGE,
    PROFILE_CAD_INTERCHANGE,
    PROFILE_INTERACTIVE,
    PROFILE_MPEG4_INTERACTIVE,
    PROFILE_IMMERSIVE,
    PROFILE_FULL
};

typedef enum {
    XZ_DIRECTION,
    XY_DIRECTION,
    YZ_DIRECTION
} Direction;

enum xmlWriteFlag {
    XML_PROTO_INSTANCE_FIELD,
    XML_IN_TAG,
    XML_IS,
    XML_NODE
};

class NodeData {
public:
                      NodeData(Scene *scene, Proto *proto);
                      NodeData(const Node &node);
    virtual          ~NodeData();

    void              delete_this(void);
    bool              isClassType(int type) { return type >= ANY_NODE; }
    bool              matchNodeClass(int childType) const;

    virtual int       write(int filedes, int indent);
    virtual int       writeXml(int filedes, int indent);
    virtual int       writeProto(int filedes);
    int               writeProto(int f, const char *urn, 
                                 const char *directoryName,
                                 const char *haveUrl = "",
                                 bool nameInUrl = true);
    int               writeX3dProto(int filedes);

    int               writeProtoArguments(int filedes) const;
    virtual bool      avoidProtoOnPureVrml(void) { return false; }
    virtual bool      canWriteAc3d();
    virtual int       writeAc3d(int filedes, int indent);
    virtual int       writeAc3dMaterial(int filedes, int indent, 
                                          const char *name) { return 0; }
    virtual void      setAc3dMaterialIndex(int index) {}
    virtual int       getIncAc3dMaterialIndex(void) { return 0; }
    virtual void      handleAc3dMaterial(ac3dMaterialCallback callback, 
                                         Scene* scene);

    virtual bool      canWriteLdrawDat();
    virtual int       writeLdrawDat(int filedes, int indent);

    Scene            *getScene() const { return _scene; }
    virtual FieldValue *getField(int index) const;
    virtual void        setField(int index, FieldValue *value);

    virtual FieldValue *getField(FieldIndex index) const
                           { return getField((int) index); }
    virtual void        setField(FieldIndex index, FieldValue *value)
                           { setField((int) index, value); }

    const char       *getTreeLabel(void) { return _treeLabel; }
    const MyString   &getName(bool newName = false);
    // setName should only be called from Scene::def
    void              setName(const char *name);
    bool              hasName(void);
    bool              needsDEF() const;

    virtual Node     *getConvertedNode(void) { return NULL; }       
    void              setConvertedNode(void) 
                         { _convertedNode = getConvertedNode(); }
    void              deleteConvertedNode(void);

    bool              needExtraJavaClass(void);
    bool              writeJavaOutsideClass(int languageFlag);

    void              getGraphPosition(float *x, float *y) const
                         { *x = _graphX; *y = _graphY; }
    void              setGraphPosition(float x, float y)
                         { _graphX = x; _graphY = y; }

    void              getGraphSize(int *width, int *height) const
                         { *width = _graphWidth; *height = _graphHeight; }
    void              setGraphSize(int width, int height)
                         { _graphWidth = width; _graphHeight = height; }

    void              ref() { _refs++; }
    void              unref() 
                         { 
                         if (--_refs == 0) 
                             delete_this(); 
                         }
    void              ref0() { if (this != NULL) _refs = 0; }
    int               getRefs() { return _refs; }

    virtual void      onAddRoute(Node *s, int out, Node *d, int in) {}

    virtual int       getType() const;
    virtual int       getNodeClass() const;
    virtual int       getProfile(void) const { return -1; }

    virtual const char* getComponentName(void) const { return ""; }
    virtual int       getComponentLevel(void) const { return -1; }

    int               getMaskedNodeClass(void);

    virtual Node     *copy() const = 0;
    void              copyData(const NodeData &node);

    int               findChild(Node *child, int field) const;

    int               lookupEventIn(const MyString &name, bool x3d) const;
    int               lookupEventOut(const MyString &name, bool x3d) const;

    Proto            *getProto() const { return _proto; }
    virtual Proto    *getPrimaryProto() const { return getProto(); }
 
    void              addInput(int eventIn, Node *src, int eventOut);
    void              addOutput(int eventOut, Node *dst, int eventIn);
    void              removeInput(int eventIn, Node *src, int eventOut);
    void              removeOutput(int eventOut, Node *dst, int eventIn);
    const SocketList &getInput(int i) const { return _inputs[i]; }
    const SocketList &getOutput(int i) const { return _outputs[i]; }

    virtual void      update();
    virtual void      reInit();

    virtual void      updateTime() {}

    virtual bool      validate(void) { return true; }

    virtual void      setInternal(bool flag) {}

    virtual bool      hasNumbers4kids(void) { return false; }

    virtual bool      maySetDefault(void) { return true; }

    Node             *getParent(int index) const 
                         { return index == -1 ? NULL: _parents[index]._node; }
    int               getParentField(int index) const 
                         { return index == -1 ? -1 : _parents[index]._field; }

    int               getNumParents() const { return _parents.size(); }
    void              copyParentList(const Node &node);

    bool              checkValidX3d(Element *field);
    bool              validChild(int field, Node *child);
    bool              validChildType(int field, int childType);
    int               findValidField(Node *child);
    int               findValidFieldType(int childType);
    int               findFirstValidFieldType(int childType);

    bool              getFlag(int flag) const 
                         { return (_flags & (1 << flag)) != 0; }
    void              setFlag(int flag) { _flags |= (1 << flag); }
    void              setFlagRec(int flag);
    void              clearFlag(int flag) { _flags &= ~(1 << flag); }
    void              clearFlagRec(int flag);

    bool              isCollapsed() const 
                         { return getFlag(NODE_FLAG_COLLAPSED); }

    virtual void      transform() {}
    virtual void      transformBranch() {}
    virtual void      transformForHandle(int /* handle */) {}
    virtual void      preDraw() {}
    virtual void      draw() {}
    virtual void      draw(int pass) {}
    bool              canDraw() { return _canDraw; }
    virtual void      bind() {}
    virtual void      unbind() {}
    virtual void      drawHandles() {}
    virtual void      drawNormals() {}
    /// countPolygons() do not count polygons in primitives
    virtual int       countPolygons(void) {return 0;}
    virtual int       countPrimitives(void) {return 0;}
    virtual int       countPolygons1Sided(void) {return 0;}
    virtual int       countPolygons2Sided(void) {return 0;}

    virtual bool      isMesh(void) { return _isMesh; }

    virtual bool      hasTwoSides(void) { return false; }
    virtual bool      isDoubleSided(void) { return false; }
    virtual void      toggleDoubleSided(void) {}
    virtual int       getConvexField() { return -1; }
    virtual int       getNormalField() { return -1; }
    virtual int       getTexCoordField() { return -1; }
    virtual int       getSolidField() { return -1; }
    virtual void      flipSide(void) {}

    virtual bool      validHandle(int handle) { return true; }
    virtual Vec3f     getHandle(int handle, int *constraint, int *field)
                         { 
                         *field = -1;
                         return Vec3f(0.0f, 0.0f, 0.0f); 
                         }
    virtual void      setHandle(int /* handle */, const Vec3f & /* v */) {}

    virtual void      sendEvent(int eventOut, double timestamp, FieldValue *value);
    virtual void      receiveEvent(int eventIn, double timestamp, FieldValue *value);

    virtual bool      isInterpolator() { return false; }

    virtual bool      hasProtoNodes(void) { return false; }

    //nurbs conversion virtual
    virtual Node      *toNurbs() {return NULL;}
    virtual Node      *toNurbs(int nshell, int narea, int narcs, 
                               int uDegree, int vDegree) {return NULL;}
    virtual Node      *toNurbs(int narcslong,  int narcslat, 
                               int uDegree, int vDegree) {return NULL;}
    virtual Node      *toNurbs(int nAreaPoints, int Degree) {return NULL;}
    virtual Node      *toNurbs(int narcs, int pDegree, float rDegree, 
                               int axis) {return NULL;}
    virtual Node      *toNurbs(int narcs, int pDegree, float uDegree, 
                               Vec3f &P1, Vec3f &P2) {return NULL;}
    virtual Node      *degreeElevate(int newDegree) {return NULL;}
    virtual Node      *degreeElevate(int newUDegree, int newVDegree)
                          {return NULL;}

    // mesh conversion virtual
    virtual Node     *toIndexedFaceSet(int meshFlags = MESH_WANT_NORMAL,
                                       bool cleanVertices = true)
                          { return NULL; }
    virtual bool       canConvertToIndexedFaceSet(void) { return false; }

    // indexed triangle set conversion virtual
    virtual Node      *toIndexedTriangleSet(int meshFlags = MESH_TARGET_HAS_CCW)
                          { return NULL; }
    virtual bool       canConvertToIndexedTriangleSet(void) { return false; }
    virtual bool       shouldConvertToIndexedTriangleSet(void) 
                          { return canConvertToIndexedTriangleSet(); }

    // triangle set conversion virtual
    virtual Node      *toTriangleSet(int meshFlags = MESH_TARGET_HAS_CCW) 
                          { return NULL; }
    virtual bool       canConvertToTriangleSet(void) { return false; }
    virtual bool       shouldConvertToTriangleSet(void)
                          { return canConvertToTriangleSet(); }

    // chain conversion virtual
    virtual Node      *toIndexedLineSet(void) { return NULL; }
    virtual bool       canConvertToIndexedLineSet(void) { return false; }

    // extrusion conversion virtual
    virtual Node      *toExtrusion(void) { return NULL; }
    virtual bool       canConvertToExtrusion(void) { return false; }

    // convertion to interpolators
    virtual bool       canConvertToPositionInterpolator(void) 
                          { return false; }
    virtual Node       *toPositionInterpolator(void)
                           { return NULL; }

    virtual bool        canConvertToOrientationInterpolator(void) 
                           { return false; }
    virtual Node       *toOrientationInterpolator(Direction direction)
                            { return NULL; }
    /// compare content
    bool                isEqual(Node* Node);
    friend bool         isEqual(Node* Node);

    MyString            newEventName(int typeEnum, bool out);

    bool                hasFieldFlag(int flag);
    bool                hasRoute(SocketList socketlist);

    virtual bool        isInvalidChildNode(void)
                           {
                           // true if node may not be part of a MFNode field
                           // of a other node (or at root of scenegraph)
                           return false;
                           }

    virtual bool        isCoverNode(void) { return false; }
    virtual bool        hasCoverFields(void) { return false; }
    bool                hasCoverDefault() { return hasDefault(FF_COVER_ONLY); }
    virtual bool        isKambiNode(void) { return false; }
    virtual bool        hasKambiFields(void) { return false; }
    bool                hasKambiDefault() { return hasDefault(FF_KAMBI_ONLY); }
    bool                hasX3dDefault() { return hasDefault(FF_X3D_ONLY); }
    bool                hasDefault(int flag);

    virtual void        setNormalFromMesh(Node *nnormal) {}
    virtual void        setTexCoordFromMesh(Node *ntexCoord) {}

    virtual bool        isTransparent(void) { return false; }
    virtual float       getTransparency(void) { return 0; }

    virtual bool        isFlat(void) { return false; }

    virtual Node       *getColorNode() { return NULL; }

    void                handleIs(void);
    Node               *getIsNode(int nodeIndex);
    void                setScene(Scene *scene) { _scene = scene; }
    bool                isInsideProto(void) { return _inSideProto; }
    void                setInsideProto(bool f = true) { _inSideProto = f; }
    void                setNodePROTO(NodePROTO *node) 
                           { 
                           _nodePROTO = node; 
                           _inSideProto = true;
                           }
    NodePROTO          *getNodePROTO(void) { return _nodePROTO; }
    void                removeChildren(void);
    bool                isDefault(int field) const;
    bool                hasInputs(void);
    bool                hasOutputs(void);
    bool                hasInput(const char* routename) const;
    bool                hasOutput(const char* routename) const;
    int                 writeRoutes(int f, int indent) const;

    void                generateTreeLabel(void);

    void                setDefault(void);
    virtual void        flatten(int direction, bool zero) {}
    virtual bool        canFlatten(void) {return false;}

    virtual Node       *convert2X3d(void);
    virtual Node       *convert2Vrml(void);

    virtual void        setupFinished(void) {}

    virtual int         getChildrenField(void) const { return -1; }

    const char         *getVariableName(void);
    void                setVariableName(const char *name);

    const char         *getClassName(void);

    virtual bool        isDynamicFieldsNode(void) { return false; }

    virtual bool        isPROTO(void) { return false; }

protected:
    const char         *searchIsName(int i, int type);

    int                 writeIs(int f, int indent, 
                                const char *name, const char * isName);
    virtual int         writeFields(int f, int indent);
    int                 writeField(int f, int indent, int i, 
                                   bool script = false);
    int                 writeEventIn(int f, int indent, int i, 
                                     bool eventName = false);
    int                 writeEventOut(int f, int indent, int i, 
                                      bool eventName = false);

    int                 writeEventInStr(int f);
    int                 writeEventOutStr(int f);
    int                 writeFieldStr(int f);
    int                 writeExposedFieldStr(int f);

    int                 writeXmlIs(int f, int indent, 
                                   const char *name, const char *isName);
    int                 writeXmlProtoInstanceField(int f, int indent, 
                                                   const char *name, 
                                                   FieldValue *value); 
    int                 writeXmlFields(int f, int indent, int when);
    int                 writeXmlField(int f, int indent, int i, int when,
                                      bool script = false);
    int                 writeXmlEventIn(int f, int indent, int i, int when,
                                        bool eventName = false);
    int                 writeXmlEventOut(int f, int indent, int i, int when,
                                         bool eventName = false);

protected:
    Scene              *_scene;
    ParentArray         _parents;
    MyString            _name;
    MyString            _treeLabel;
    MyString            _variableName;
    Node               *_convertedNode;
    int                 _refs;
    int                 _flags;
    Proto              *_proto;
    FieldValue        **_fields;
    int                 _numFields;
    int                 _numEventIns;
    int                 _numEventOuts;
    SocketList         *_inputs;
    SocketList         *_outputs;
    float               _graphX, _graphY;
    int                 _graphWidth, _graphHeight;
    unsigned long       _identifier;
    bool                _inSideProto;
    NodePROTO          *_nodePROTO;
    bool                _isMesh;
    bool                _canDraw;
};
   

typedef bool (*DoWithNodeCallback)(Node *node, void *data);
typedef bool (*DoWithSimilarBranchCallback)(Node *node, Node *similarNode, 
                                            void *data);
typedef void (*DoWithAllElementsCallback)(Element *element, void *data);

class Node : public NodeData
{
public:
                        Node(Scene *scene, Proto *proto);
                        Node(const Node &node);
                        Node(const Node &node, Proto *proto);

    virtual            ~Node();

    // macros not needed: fieldMacros(SFNode, metadata, Proto)

    void                addParent(Node *parent, int field);
    void                removeParent(void);
    bool                hasParent(void) const
                           { 
                           if (getNumParents() <= 0) 
                               return false;
                           if (_geometricParentIndex == -1)
                               return false;
                           if (_geometricParentIndex >= getNumParents())
                               return false;
                           return (getParent() != NULL);
                           }
    Node               *getParent(void) const 
                           { 
                           if (_parents.size() == 0)
                               return NULL;
                           if (_parents.size() == 1)
                               return NodeData::getParent(0);
                           return NodeData::getParent(_geometricParentIndex);
                           }
    bool                hasParentOrProtoParent(void) const
                           { return (getParentOrProtoParent() != NULL); }
    Node               *getParentOrProtoParent(void) const;
    int                 getParentField(void) const 
                           { 
                           if (_parents.size() == 1)
                               return NodeData::getParentField(0);
                           return 
                                NodeData::getParentField(_geometricParentIndex);
                           }
    int                 getParentFieldOrProtoParentField(void) const;
    Node               *searchParent(int nodeType) const; 
    int                 getParentIndex(void) const;
    FieldValue         *getParentFieldValue(void) const;

    bool                isInScene(Scene* scene) const;
    virtual void        addFieldNodeList(int index, NodeList *value);
    bool                hasAncestor(Node *node) const;
    bool                supportAnimation(void);
    bool                supportInteraction(void);
    virtual int         getAnmationCommentID(void) { return -1; }
    virtual int         getInteractionCommentID(void) { return -1; }
    virtual bool        isInvalidChild(void);
    virtual bool        hasBoundingBox(void) { return false; }
    virtual Vec3f       getMinBoundingBox(void);
    virtual Vec3f       getMaxBoundingBox(void);
    virtual void        flip(int index) {}
    virtual void        swap(int fromTo) {}
    virtual bool        showFields() { return false; }
    virtual bool        isEXTERNPROTO(void) { return false; }

    void                appendTo(NodeList* nodelist);
    void                appendComment(Node *node);

    void                doWithParents(DoWithNodeCallback callback, void *data,
                                      bool searchInRest = true, 
                                      bool callSelf = true);
    void                doWithSiblings(DoWithNodeCallback callback, void *data,
                                       bool searchInRest = true, 
                                       bool callSelf = true);

    bool                doWithBranch(DoWithNodeCallback callback, void *data,
                                     bool searchInRest = true, 
                                     bool skipBranch = false,
                                     bool skipProto = false,
                                     bool callSelf = true);

    bool                doWithSimilarBranch(DoWithSimilarBranchCallback 
                                            callback, Node *similarNode, 
                                            void *data);

    void                doWithAllElements(DoWithAllElementsCallback callback, 
                                          void *data);

    parentFlag          getParentFlag(int index) const 
                              { 
                              return _parents.get(index)._parentFlag; 
                              }

    void                setParentFlag(int index, parentFlag flag) 
                              { 
                              Parent parent = _parents.get(index);
                              _parents[index]._parentFlag = flag; 
                              }

    bool                isFirstUSE(void)
                           { 
                           if (isPROTO())
                              return _geometricParentIndex == 1; 
                           else
                              return _geometricParentIndex == 0; 
                           }
    bool                isUnused(void) { return _geometricParentIndex == -1; }

    void                copyChildrenTo(Node *copyedNode);

    int                 getPrevSiblingIndex(void);
    int                 getNextSiblingIndex(void);

    Node               *getPrevSibling(void);
    Node               *getNextSibling(void);

    virtual bool        isJoint(void) { return false; }
    virtual bool        isHumanoid(void) { return false; }

    int                 writeC(int filedes, int languageFlag);
    int                 writeCDataAsFunctions(int filedes, int languageFlag);
    int                 writeCDataAsClasses(int filedes, int languageFlag);
    int                 writeCDataFunctions(int filedes, int languageFlag);
    int                 writeCField(int f, int i, int languageFlag, 
                                    bool nodeFlag);
    int                 writeCFieldFunction(int f, int i, int languageFlag, 
                                            bool nodeFlag);
    int                 writeCFieldClass(int f, int i, int languageFlag, 
                                         bool nodeFlag);
    int                 writeCVariable(int f, int languageFlag);
    virtual void        writeCWarning(void) {}

    virtual bool        canWriteCattGeo();
    virtual int         writeCattGeo(int filedes, int indent);
    int                 getGeometricParentIndex(void) const
                           { return _geometricParentIndex; }
    Path               *getPath() const;

    virtual char       *buildExportMaterialName(const char *name)
                           {
                           return mystrdup(name);
                           }
    char*               getExportMaterialName(const char *defaultName);

protected:
    int                 _geometricParentIndex;
    NodeList           *_commentsList;
    int                 _numberCDataFunctions;
};

#endif // _NODE_H
