/*
 * Node.cpp
 *
 * 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.
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "stdafx.h"

#include "Node.h"
#include "Scene.h"
#include "Field.h"
#include "FieldValue.h"
#include "FieldCommand.h"
#include "Proto.h"
#include "Path.h"
#include "SFNode.h"
#include "MFNode.h"
#include "SFString.h"
#include "MFString.h"
#include "EventIn.h"
#include "EventOut.h"
#include "ExposedField.h"
#include "URL.h"
#include "DuneApp.h"
#include "NodeScript.h"

#define HANDLE_SIZE 2.0f

NodeData::NodeData(Scene *scene, Proto *proto)
{
    static unsigned long identifier_source=0;
    identifier_source++;
    _identifier=identifier_source;

    _scene = scene;
    _graphX = _graphY = 0;
    _graphWidth = _graphHeight = 0;
    _refs = 0;
    _flags = 1<<NODE_FLAG_COLLAPSED;
    _proto = proto;

    bool x3d = scene->isX3d();

    int i;
    _numFields = _proto->getNumFields();
    _fields = new FieldValue *[_numFields];
    for (i = 0; i < _numFields; i++) {
        _fields[i] = _proto->getField(i)->getDefault(x3d);
        if (_fields[i]) {
            _fields[i] = _fields[i]->copy();
            _fields[i]->ref();
        }
    }
    _numEventIns = _proto->getNumEventIns();
    _inputs = new SocketList[_numEventIns];
    _numEventOuts = _proto->getNumEventOuts();
    _outputs = new SocketList[_numEventOuts];
    _inSideProto = false;
    _nodePROTO = NULL;
    _isMesh = false;
    _canDraw = true;
    handleIs();
    generateTreeLabel();
    _variableName = "";
    _convertedNode = NULL;
    _scene->addNode((Node*)this);
}

NodeData::NodeData(const Node &node) {
    copyData(node);
}    
    
void
NodeData::copyData(const NodeData &node)
{
    _identifier=node._identifier;  // FIXME: unclear: should all IDs be unique??

    _scene = node._scene;
    _refs = 0;
    _graphX = _graphY = 0;
    _graphWidth = _graphHeight = 0;
    _flags = node._flags;
    _proto = node._proto;
    _numFields = _proto->getNumFields();
    _fields = new FieldValue *[_numFields];
    if (node._name.length() != 0)
        if (!_scene->hasAlreadyName(node._name)) 
            _scene->def(node._name, (Node *)this);
        else
            _scene->makeSimilarName((Node *)this, node._name);
    for (int i = 0; i < _numFields; i++) {
        _fields[i] = node._fields[i]->copy();
        _fields[i]->ref();
    }
    _numEventIns = _proto->getNumEventIns();
    _inputs = new SocketList[_numEventIns];
    _numEventOuts = _proto->getNumEventOuts();
    _outputs = new SocketList[_numEventOuts];
    _inSideProto = node._inSideProto;
    _nodePROTO = node._nodePROTO;
    _isMesh = node._isMesh;
    _canDraw = node._canDraw;
    handleIs();
    generateTreeLabel();        
    _variableName = node._variableName;
    _convertedNode = node._convertedNode;
    _scene->addNode((Node*)this);
 }

NodeData::~NodeData()
{
    unref();
}

void 
NodeData::delete_this(void)
{
    for (int i = 0; i < _numFields; i++) {
        _fields[i]->unref();
    }
    _numFields = 0;
    delete [] _fields;
    delete [] _inputs;
    delete [] _outputs;
    _scene->undef(_name);
    _scene->removeNode((Node *)this);
}

Node::Node(Scene *scene, Proto *proto) : NodeData(scene,proto) 
{
    _commentsList = new NodeList;
    _geometricParentIndex = -1;     
    ref();
    _numberCDataFunctions = 0;
}

Node::Node(const Node &node) : NodeData(node)
{
    _geometricParentIndex = node.getGeometricParentIndex();
    _commentsList = new NodeList;
    ref();
    _numberCDataFunctions = 0;
}

Node::Node(const Node &node, Proto *proto) : NodeData(node)
{ 
    _geometricParentIndex = node.getGeometricParentIndex();
    _proto = proto;
    for (int i = 0; i < proto->getNumEventOuts(); i++)
        _outputs[i] = node._outputs[i];
    _commentsList = new NodeList;
    ref();
    _numberCDataFunctions = 0;
}

Node::~Node()
{
    delete _commentsList;
}

bool
NodeData::matchNodeClass(int childType) const
{ 
    return _proto->matchNodeClass(childType); 
}

void
NodeData::copyParentList(const Node &node)
{ 
    for (int i = 0; i < node._parents.size(); i++)
        _parents.append(node._parents[i]);
}

int         
NodeData::getType() const 
{ 
    if (_proto) 
        return _proto->getType(); 
    return -1; 
}

int
NodeData::getNodeClass() const
{ 
    if (_proto) 
        return _proto->getNodeClass(); 
    return CHILD_NODE; 
}

int                
NodeData::getMaskedNodeClass(void)
{ 
    if (_proto)
        return ::getMaskedNodeClass(getNodeClass()); 
    return 0;
}

bool
NodeData::hasName(void)
{
    if (_name.length() == 0)
        if (needsDEF())
            _scene->generateUniqueNodeName((Node *)this);       
    if (_name.length() == 0) 
        return false;
    else
        return true;
}

const MyString& 
NodeData::getName(bool newName)
{
    if (newName || needsDEF())
       if (_name.length() == 0) 
          _scene->generateUniqueNodeName((Node *)this);       
    return _name; 
}

void
NodeData::setName(const char *name)
{
    _scene->undef(_name);
    _name = name; 
    generateTreeLabel();
}

bool
NodeData::needsDEF() const
{
    if (_name.length() != 0) return true;

    if (((Node *)this)->getNumParents() > 1) return true;

    for (int i = 0; i < _numEventIns; i++) {
        if (_inputs[i].size() > 0) {
            return true;
        }
    }

    for (int j = 0; j < _numEventOuts; j++) {
        if (_outputs[j].size() > 0) {
            return true;
        }
    }

    return false;
}

// C/C++/java keywords not possible as variable names
static const char *keyWords[] = {
    "abstract",
    "asm",
    "auto",
    "bool",
    "boolean",
    "break",
    "byte",
    "case",
    "catch",
    "char",
    "class",
    "const",
    "continue",
    "default",
    "delete",
    "do",
    "double",
    "else",
    "enum",
    "extends",
    "extern",
    "final",
    "finally",
    "float",
    "for",
    "friend",
    "goto",
    "if",
    "implements",
    "import",
    "inline",
    "instanceof",
    "int",
    "interface",
    "long",
    "native",
    "new",
    "operator",
    "package",
    "private",
    "protected",
    "public",
    "register",
    "return",
    "short",
    "signed",
    "sizeof",
    "static",
    "strictfp",
    "String",
    "struct",
    "super",
    "switch",
    "synchronized",
    "template",
    "this",
    "throw",
    "throws",
    "transient",
    "try",
    "typedef",
    "union",
    "unsigned",
    "virtual",
    "void",
    "volatile",
    "while"
};

const char *
NodeData::getVariableName(void)
{ 
    MyString cName = "";
    if (isalpha(_name[0]))
        cName += _name[0];
    else
        cName += "A";  
    for (int i = 1; i < _name.length(); i++)
        if (isalnum(_name[i]))
            cName += _name[i];
        else
            cName += "_";

    const char *name = NULL;
    bool isRoot = false;
    if (_variableName.length() == 0) {
        if (_scene != NULL) {
            if (_scene->getRoot() == this) {
                isRoot = true;
                _variableName = "";
                _variableName += "root";
            }
        }
        if ((!isRoot) && hasName()) {
            _variableName = "";
            bool isKeyWord = false;
            for (int i = 0; i < sizeof(keyWords)/sizeof(const char *); i++)
                if (strcmp(_name.getData(), keyWords[i]) == 0) {
                    isKeyWord = true;
                    _variableName += _scene->getUniqueNodeName(cName);
                    swDebugf("Warning: Variablename ");
                    swDebugf("\"%s\"", _name.getData());
                    swDebugf(" is a C++/java keyword, ");
                    swDebugf("\"%s\"", _variableName.getData());
                    swDebugf(" used instead\n");
                }
            if (!isKeyWord)
                _variableName += cName;           
        }
        if (_variableName.length() == 0)
            if (_scene != NULL) {
                _variableName = "";
                _variableName += _scene->generateVariableName((Node *)this);
            }
    }

    return _variableName;
}    

void                
NodeData::setVariableName(const char *name)
{
    _variableName = "";
    _variableName += name;
}

const char *
NodeData::getClassName(void) 
{
    if (_proto)
        return _proto->getClassName();
    return NULL;
}


FieldValue *
NodeData::getField(int index) const
{
#ifdef DEBUG
    assert(index >= 0 && index < _numFields);
#else
    if ((index < 0) && (index >= _numFields)) {
        printf("Internal error in NodeData::getField\n");
        return NULL;
    }
#endif
    return _fields[index];
}

void
NodeData::setField(int index, FieldValue *value)
{
    assert(index >= 0 && index < _numFields);
    Field *field = _proto->getField(index);
    if (field != NULL)
        assert(field->getType() == value->getType());

    // if field is an SFNode or MFNode type, remove old values from 
    // children's parent list

    if (_fields[index]->getType() == SFNODE) {
        Node *child = ((SFNode *) _fields[index])->getValue();
        if (child) child->removeParent();
    } else if (_fields[index]->getType() == MFNODE) {
        NodeList *childList = ((MFNode *) _fields[index])->getValues();
        if (childList) {
            for (int i = 0; i < childList->size(); i++) {
                Node *child = childList->get(i);
                if (child) child->removeParent();
            }
        }
    }

    value->clamp(field->getMin(), field->getMax());

    if (_fields[index] != NULL)
        _fields[index]->unref();
    _fields[index] = value;
    _fields[index]->ref();

    if (value->getType() == SFNODE) {
        Node *child = ((SFNode *) value)->getValue();
        if (child) child->addParent((Node*)this, index);
    } else if (value->getType() == MFNODE) {
        NodeList *childList = ((MFNode *) value)->getValues();
        if (childList) {
            for (int i = 0; i < childList->size(); i++) {
                Node *child = childList->get(i);
                if (child) child->addParent((Node*)this, index);
            }
        }
    }
    // handle IS
    if (field && (field->getFlags() & FF_IS))
        for (int i = 0; i < field->getNumIs(); i++) {
            if (field->getIsNodeIndex(i) >= 0) {
                Node *isNode = getIsNode(field->getIsNodeIndex(i));
                if (isNode)
                    isNode->setField(field->getIsField(i), value);
            }
        }
    ExposedField *expField = field->getExposedField();
    if (expField && (expField->getFlags() & FF_IS))
        for (int i = 0; i < expField->getNumIs(); i++) {
            if (expField->getIsNodeIndex(i) >= 0) {
                Node *isNode = getIsNode(expField->getIsNodeIndex(i));
                if (isNode)
                    isNode->setField(expField->getIsField(i), value);
            }
        }
}

void
Node::addFieldNodeList(int index, NodeList *childList)
{
    assert(index >= 0 && index < _numFields);
    if (((MFNode*)_fields[index])->getSize() == 0)
        setField(index, new MFNode(childList));
    else {
        for (int i = 0; i < childList->size(); i++) {
            Node *child = childList->get(i);
            FieldValue* newField= ((MFNode*)_fields[index])->addNode(child);
            newField->clamp(_proto->getField(index)->getMin(), 
                            _proto->getField(index)->getMax());

            _fields[index]->unref();
            _fields[index] = newField;
            _fields[index]->ref();
            if (child) {
                child->addParent(this, index);
            }
        }
    }
    ((MFNode*)_fields[index])->getValues();
}

int 
NodeData::write(int f, int indent)
{
    bool x3d = _scene->isX3dv();
    if (_proto) {
        TheApp->checkSelectionLinenumberCounting(_scene, (Node*) this);
        if (getFlag(NODE_FLAG_DEFED)) {
            RET_ONERROR( mywritestr(f, "USE ") )
            RET_ONERROR( mywritestr(f, (const char *) _name) )
            RET_ONERROR( mywritestr(f, "\n") )
            TheApp->incSelectionLinenumber();
        } else {
            if (((Node *)this)->needsDEF()) {
                if (!_name[0]) _scene->generateUniqueNodeName((Node*)this);
                RET_ONERROR( mywritestr(f, "DEF ") )
                RET_ONERROR( mywritestr(f, (const char *) _name) )
                RET_ONERROR( mywritestr(f, " ") )
            }
            setFlag(NODE_FLAG_DEFED);
            bool writeProtoName = true;
            if (_scene->isPureVRML97())
                if ((TheApp->getCoverMode() && (!hasDefault(FF_COVER_ONLY))) ||
                    (TheApp->getKambiMode() && (!hasDefault(FF_KAMBI_ONLY)))) {
                    Proto *extension = _scene->getExtensionProto(_proto);
                    if (extension != NULL) {
                        writeProtoName = false;
                        RET_ONERROR( mywritestr(f, extension->getName(x3d)) )
                    }
                }
            if (writeProtoName)
                RET_ONERROR( mywritestr(f, (const char *) _proto->getName(x3d)))

            if (!TheApp->GetkrFormating()) {
                RET_ONERROR( mywritestr(f, "\n") )
                TheApp->incSelectionLinenumber();
                RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) )
            } else
                RET_ONERROR( mywritestr(f, " ") )

            RET_ONERROR( mywritestr(f, "{\n") )
            TheApp->incSelectionLinenumber();
            RET_ONERROR( writeFields(f, indent + TheApp->GetIndent()) )
            if (!TheApp->GetkrFormating())
                RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) )
            else
                RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f, "}\n") )
            TheApp->incSelectionLinenumber();
            if (indent==0) {
                RET_ONERROR( mywritestr(f, "\n") )
                TheApp->incSelectionLinenumber();
            }
            RET_ONERROR( writeRoutes(f, indent) )
            setFlag(NODE_FLAG_TOUCHED);
        }
    }
    return(0);
}

int
NodeData::writeXml(int f, int indent)
{
    bool x3d = true;
    if (getType() == VRML_COMMENT)
        return 0;
    if (_proto) {
        Proto *protoToWrite = NULL;
        TheApp->checkSelectionLinenumberCounting(_scene, (Node*) this);
        RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f, "<") )
        bool writeProtoInstance = true;
        bool isExtensionPROTO = false;
        if (getType()== DUNE_VRML_CUT)
            isExtensionPROTO = true;
        if (getType()== DUNE_VRML_SCENE)
            isExtensionPROTO = true;
        if (_scene->isPureVRML97() &&
            ((TheApp->getCoverMode() && (!hasDefault(FF_COVER_ONLY))) ||
             (TheApp->getKambiMode() && (!hasDefault(FF_KAMBI_ONLY))))) {
            protoToWrite = _scene->getExtensionProto(_proto);
        } else if (isPROTO() || isExtensionPROTO) {
            protoToWrite = _proto;
        }    
        if (protoToWrite == NULL)
            RET_ONERROR( mywritestr(f, (const char *) _proto->getName(x3d)))
        else {
            RET_ONERROR( mywritestr(f, "ProtoInstance name='") )
            RET_ONERROR( mywritestr(f, protoToWrite->getName(x3d)) )
            RET_ONERROR( mywritestr(f, "'") )
        }

        if (getFlag(NODE_FLAG_DEFED)) {
            RET_ONERROR( mywritestr(f, " USE='") )
            RET_ONERROR( mywritestr(f, (const char *) _name) )
            RET_ONERROR( mywritestr(f, "' />\n") )
            TheApp->incSelectionLinenumber();
        } else {
            if (((Node *)this)->needsDEF()) {
                if (!_name[0]) _scene->generateUniqueNodeName((Node*)this);
                RET_ONERROR( mywritestr(f, " DEF='") )
                RET_ONERROR( mywritestr(f, (const char *) _name) )
                RET_ONERROR( mywritestr(f, "' ") )
                setFlag(NODE_FLAG_DEFED);
            }
            RET_ONERROR( mywritestr(f, " ") )
            RET_ONERROR( writeXmlFields(f, indent, XML_IN_TAG) )
            RET_ONERROR( mywritestr(f, ">\n") )
            TheApp->incSelectionLinenumber();
            RET_ONERROR( writeXmlFields(f, indent + TheApp->GetIndent(), 
                                        XML_NODE) )
            RET_ONERROR( writeXmlFields(f, indent + TheApp->GetIndent(), 
                                        XML_PROTO_INSTANCE_FIELD) )
            RET_ONERROR( writeXmlFields(f, indent + TheApp->GetIndent(), 
                                        XML_IS) )
            RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f, "</") )
            if (protoToWrite == NULL)
                RET_ONERROR( mywritestr(f, (const char *) _proto->getName(x3d)))
            else
                RET_ONERROR( mywritestr(f, "ProtoInstance") )
            RET_ONERROR( mywritestr(f, ">\n") )
            TheApp->incSelectionLinenumber();
            RET_ONERROR( writeRoutes(f, indent) )
            setFlag(NODE_FLAG_TOUCHED);
        }
    }
    return 0;
}

int            
NodeData::writeProto(int filedes)
{
    // used to write the EXTERNPROTO definition of extension nodes
    return 0;
}

int
NodeData::writeProto(int f, const char *urn, const char *directoryName,
                           const char *haveUrl, bool nameInUrl)
{
    const char* nodeName = _proto->getName(_scene->isX3d());
    RET_ONERROR( mywritef(f, "EXTERNPROTO %s[\n", nodeName) )    
    TheApp->incSelectionLinenumber();
    RET_ONERROR( writeProtoArguments(f) )
    RET_ONERROR( mywritestr(f, " ]\n") )
    TheApp->incSelectionLinenumber();
    RET_ONERROR( mywritestr(f, "[\n") )
    TheApp->incSelectionLinenumber();
    if (strlen(urn) > 0) {
        RET_ONERROR( mywritef(f, "  \"%s:%s\"\n", urn, nodeName) )
        TheApp->incSelectionLinenumber();
    }
    RET_ONERROR( mywritef(f, "  \"%sPROTO.wrl\"\n", nodeName) )
    TheApp->incSelectionLinenumber();
    RET_ONERROR( mywritestr(f, "  \"") )
    char *dunedocs = getenv("DUNEDOCS");
    if (dunedocs != NULL) {
        RET_ONERROR( mywritestr(f, dunedocs) )
        RET_ONERROR( mywritestr(f, "/") )
        RET_ONERROR( mywritestr(f, directoryName) )
        RET_ONERROR( mywritestr(f, "/") )
    } else if (strlen(haveUrl) > 0) {
        RET_ONERROR( mywritestr(f, haveUrl) )
        if (nameInUrl)
            RET_ONERROR( mywritestr(f, "/") )
        else
            RET_ONERROR( mywritestr(f, "\"\n") )
    }
    if ((dunedocs != NULL) || (nameInUrl))
        RET_ONERROR( mywritef(f, "%sPROTO.wrl\"\n", nodeName) )
    TheApp->incSelectionLinenumber();
    RET_ONERROR( mywritef(f, 
                          "  \"%s/docs/%s/%sPROTO.wrl\"\n",
                          "http://129.69.35.12/dune",
                          directoryName, nodeName) )
    TheApp->incSelectionLinenumber();
    RET_ONERROR( mywritestr(f, "]\n") )
    TheApp->incSelectionLinenumber();
    return 0;
}

int     
NodeData::writeX3dProto(int filedes) 
{
    return ((Node *)this)->writeProto(filedes, 
                                     "urn:web3d:x3d:node:",
                                     "x3d"
#ifdef HAVE_X3D_PROTO_URL
                                    , HAVE_X3D_PROTO_URL
#endif
                                                              );
                       }



int 
NodeData::writeIs(int f, int indent, const char *name, const char* isName)
{
    RET_ONERROR( indentf(f, indent) )
    RET_ONERROR( mywritestr(f, name) )
    RET_ONERROR( mywritestr(f, " IS ") )
    RET_ONERROR( mywritestr(f, isName) )
    RET_ONERROR( mywritestr(f, "\n") )
    TheApp->incSelectionLinenumber();
    return 0;
}

int 
NodeData::writeXmlIs(int f, int indent, const char *name, const char* isName)
{
    RET_ONERROR( indentf(f, indent) )
    RET_ONERROR( mywritestr(f, "<connect nodeField='") )
    RET_ONERROR( mywritestr(f, name) )
    RET_ONERROR( mywritestr(f, "' protoField='") )
    RET_ONERROR( mywritestr(f, isName) )
    RET_ONERROR( mywritestr(f, "' />\n") )
    TheApp->incSelectionLinenumber();
    return 0;
}


int 
NodeData::writeXmlProtoInstanceField(int f, int indent, const char *name, 
                                     FieldValue* value)
{
    bool isNode = false;
    bool needValue = true;
    if (value->getType() == SFNODE)
        if (((SFNode *)value)->getValue() == NULL)
            needValue = false;
        else
            isNode = true;
    if (value->getType() == MFNODE)
        if (((MFieldValue *)value)->getSFSize() == 0)
            needValue = false;
        else
            isNode = true; 

    RET_ONERROR( indentf(f, indent) )
    RET_ONERROR( mywritestr(f, "<fieldValue name='") )
    RET_ONERROR( mywritestr(f, name) )
    RET_ONERROR( mywritestr(f, "' ") )
    if (isNode) {
        RET_ONERROR( mywritestr(f, ">\n") )
        RET_ONERROR( indentf(f, indent) )
    } else if (needValue)
        RET_ONERROR( mywritestr(f, "value=") )
    RET_ONERROR( value->writeXml(f, indent) )        
    if (isNode) {
        RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f, "</fieldValue>\n") )
    } else { 
        RET_ONERROR( mywritestr(f, "/>\n") )
    }
    TheApp->incSelectionLinenumber();
    return 0;
}

const char *
NodeData::searchIsName(int i, int type)
{
    Element *element = NULL;
    switch (type) {
      case EL_FIELD:
        element = _proto->getField(i);
        break;
      case EL_EVENT_IN:
        element =_proto->getEventIn(i);
        break;
      case EL_EVENT_OUT:
        element =_proto->getEventOut(i);
        break;
      default:
        return NULL;
    }
    if (_scene->isInvalidElement(element))
        return NULL;
    if (!isInsideProto())
        return NULL;
    
    bool x3d = _scene->isX3d();
    const char *isName = NULL;
    bool stopLoop = false;
    for (int j = 0; j < _scene->getNumProtoNames(); j++) {
        const char *protoName = _scene->getProtoName(j);
        Proto *proto = _scene->getProto(protoName);
        int isElement = -1;
        ExposedField *exposedField = NULL;
        int field = i;
        switch (type) {
          case EL_EVENT_IN:
            exposedField = ((EventIn *)element)->getExposedField();
            if (exposedField) {
                field = exposedField->getField();
                type = EL_EXPOSED_FIELD;
            }
            isElement = proto->lookupIsEventIn((Node *)this, field, type);
            if (isElement != -1) {
                isName = proto->getEventIn(isElement)->getName(x3d);
                stopLoop = true;
            }
            break;
          case EL_EVENT_OUT:
            exposedField = ((EventOut *)element)->getExposedField();
            if (exposedField) {
                field = exposedField->getField();
                type = EL_EXPOSED_FIELD;
            }
            isElement = proto->lookupIsEventOut((Node *)this, field, type);
            if (isElement != -1) {
                isName = proto->getEventOut(isElement)->getName(x3d);
                stopLoop = true;
            }
            break;
          case EL_FIELD:
            isElement = proto->lookupIsField((Node *)this, i);
            if (isElement != -1) {
                isName = proto->getField(isElement)->getName(x3d);
                stopLoop = true;
            } else {
                isElement = proto->lookupIsExposedField((Node *)this, i);
                if (isElement != -1) {
                    isName = proto->getExposedField(isElement)->getName(x3d);
                    stopLoop = true;
                }
            }
        }
        if (stopLoop)
            break;
    }
    return isName;
}

int 
NodeData::writeFields(int f, int indent)
{
    int i;

    if (!_proto) return(0);

    // delay writing of Script.url
    int scriptUrlField = -1;
    if (getType() == VRML_SCRIPT)
        scriptUrlField = ((NodeScript *)this)->url_Field();

    for (i = 0; i < _numFields; i++) 
        if (i != scriptUrlField)
            RET_ONERROR( writeField(f, indent, i) )

    for (i = 0; i < _numEventIns; i++)
        RET_ONERROR( writeEventIn(f, indent, i) )

    for (i = 0; i < _numEventOuts; i++)
        RET_ONERROR( writeEventOut(f, indent, i) )

    if (scriptUrlField != -1)
        RET_ONERROR( writeField(f, indent, scriptUrlField) )

    return(0);
}

int 
NodeData::writeXmlFields(int f, int indent, int when)
{
    int i;

    if (!_proto) return(0);

    if (isPROTO() || (getType() == DUNE_VRML_CUT) || 
                     (getType() == DUNE_VRML_SCENE)) {
        if (when != XML_PROTO_INSTANCE_FIELD)
            return 0;    
    } else 
        if (when == XML_PROTO_INSTANCE_FIELD)
            return 0;    

    bool writeIs = false;
    if (when == XML_IS) {
        for (i = 0; i < _numFields; i++)
            if (searchIsName(i, EL_FIELD) != NULL)
                writeIs = true;
        for (i = 0; i < _numEventIns; i++)
            if (searchIsName(i, EL_EVENT_IN) != NULL)
                writeIs = true;
        for (i = 0; i < _numEventOuts; i++)
            if (searchIsName(i, EL_EVENT_OUT) != NULL)
                writeIs = true;
    }
    if (writeIs) {
        RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f, "<IS>\n") )
        TheApp->incSelectionLinenumber();                
        indent += TheApp->GetIndent();
    }

    bool isScript = false;
    int scriptUrlField = -1;
    if (getType() == VRML_SCRIPT) {
        scriptUrlField = ((NodeScript *)this)->url_Field();
        isScript = true;
    }
    for (i = 0; i < _numFields; i++)
        if (i != scriptUrlField)
            RET_ONERROR( writeXmlField(f, indent, i, when, isScript) )

    for (i = 0; i < _numEventIns; i++)
        RET_ONERROR( writeXmlEventIn(f, indent, i, when) )

    for (i = 0; i < _numEventOuts; i++)
        RET_ONERROR( writeXmlEventOut(f, indent, i, when) )

    if (scriptUrlField != -1)
        RET_ONERROR( writeXmlField(f, indent, scriptUrlField, when) )

    if (writeIs) {
        indent -= TheApp->GetIndent();
        RET_ONERROR( indentf(f, indent) )
        RET_ONERROR( mywritestr(f, "</IS>\n") )
        TheApp->incSelectionLinenumber();                
    }

    return 0;
}

int 
NodeData::writeField(int f, int indent, int i, bool script)
{
    if (!_proto) return(0);
    bool x3d = _scene->isX3d();
    const char *oldBase = _scene->getURL();
    const char *newBase = _scene->getNewURL();
    bool tempSave = _scene->isTempSave();

    Field *field = _proto->getField(i);
    if (_scene->isInvalidElement(field))
        return 0;
    FieldValue *value = _fields[i];
    const char *name = field->getName(x3d);
    const char *isName = searchIsName(i, EL_FIELD);
    if (isName)
        RET_ONERROR( writeIs(f, indent, name, isName) )
    else if (value) {
        if (script || !value->equals(field->getDefault(x3d))) {                
            RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f , name) )
            RET_ONERROR( mywritestr(f ," ") )
            if ((field->getFlags() & FF_URL) && (!TheApp->GetKeepURLs())) {
                value = rewriteField(value, oldBase, newBase);
                RET_ONERROR( value->write(f, indent) )
                if (!tempSave) {
                    setField(i, value);
                    FieldUpdate* fieldUpdate=new FieldUpdate((Node*)this, i);
                    _scene->UpdateViews(NULL, UPDATE_FIELD,
                                        (Hint *) fieldUpdate);    
                    delete fieldUpdate;
                } else {
                    delete value;
                }
            } else {
                RET_ONERROR( value->write(f, indent) )
            }
        }
    }
    return(0);
}
 
int 
NodeData::writeXmlField(int f, int indent, int i, int when, bool script)
{
    if (!_proto) return(0);
    const char *oldBase = _scene->getURL();
    const char *newBase = _scene->getNewURL();
    bool tempSave = _scene->isTempSave();
    bool x3d = _scene->isX3d();

    Field *field = _proto->getField(i);
    if (_scene->isInvalidElement(field))
        return 0;
    bool isNode = (field->getType() == SFNODE) || (field->getType() == MFNODE);
    bool isScript = field->getFlags() & FF_IN_SCRIPT;
    bool isScriptUrl = field->getFlags() & FF_SCRIPT_URL;
    bool inTag = (when == XML_IN_TAG);
    FieldValue *value = _fields[i];
    const char *name = field->getName(x3d);
    const char *isName = searchIsName(i, EL_FIELD); 
    if (when == XML_IS) {
        if (isName)
            RET_ONERROR( writeXmlIs(f, indent, name, isName) )
        else
            return 0;
    } else if (when == XML_PROTO_INSTANCE_FIELD) {
        RET_ONERROR( writeXmlProtoInstanceField(f, indent, name, value) )
    } else if (value) {
        if (inTag && isScript)
            return 0;
        if (inTag && isScriptUrl)
            return 0;
        else if (isScriptUrl) {
            RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f ,"<![CDATA[\n") )
            TheApp->incSelectionLinenumber();
            RET_ONERROR( value->writeRaw(f, indent) )
            RET_ONERROR( indentf(f, indent) )
            RET_ONERROR( mywritestr(f ,"]]>\n") )
            TheApp->incSelectionLinenumber();
        } else if (isScript) {
            int flags = _scene->getWriteFlags(); 
            const char *isName = searchIsName(i, EL_FIELD);
            bool isNull = false;
            if ((field->getType() == SFNODE) && 
                (((SFNode *)value)->getValue() == NULL))
                isNull = true;
            if (isNull)
                flags |= NULL_VALUE;
            if (isName || isNode)
                flags |= WITHOUT_VALUE;
            RET_ONERROR( field->write(f, 1, flags) )
            if (isNode && (!isNull)) 
                RET_ONERROR( value->writeXml(f, 1) )
            TheApp->incSelectionLinenumber();
        } else if (isName)
            return 0;
        else if (!inTag && !isNode)
            return 0;
        else if (inTag && isNode)
            return 0;
        else if (!value->equals(field->getDefault(x3d))) {                
            if (inTag) {
                RET_ONERROR( mywritestr(f , name) )
                RET_ONERROR( mywritestr(f ,"=") )
            } 
            if ((field->getFlags() & FF_URL) && (!TheApp->GetKeepURLs())) {
                value = rewriteField(value, oldBase, newBase);
                RET_ONERROR( value->writeXml(f, indent) )
                if (!tempSave) {
                     setField(i, value);
                     FieldUpdate* fieldUpdate=new FieldUpdate((Node*)this, i);
                     _scene->UpdateViews(NULL, UPDATE_FIELD,
                                         (Hint *) fieldUpdate);    
                     delete fieldUpdate;
                } else {
                    delete value;
                }
            } else {
                RET_ONERROR( value->writeXml(f, indent) )
            }
            if (inTag) {
                RET_ONERROR( mywritestr(f ," ") )
            } 
        }
    }
    return(0);
}

int 
NodeData::writeEventIn(int f, int indent, int i, bool eventName)
{
    if (!_proto) return(0);

    bool x3d = _scene->isX3dv();

    EventIn *eventIn = _proto->getEventIn(i);
    const char *name = eventIn->getName(x3d);
    const char *isName = searchIsName(i, EL_EVENT_IN); 
    if (isName)
        RET_ONERROR( writeIs(f, indent, name, isName) )
    else if (eventName) {
        RET_ONERROR( mywritestr(f, name) )
        RET_ONERROR( mywritestr(f, "\n") )
        TheApp->incSelectionLinenumber();
    }
    return(0);
}

int 
NodeData::writeXmlEventIn(int f, int indent, int i, int when, bool eventName)
{
    if (!_proto) return(0);

    bool x3d = _scene->isX3dv();

    EventIn *eventIn = _proto->getEventIn(i);
    bool isScript = eventIn->getFlags() & FF_IN_SCRIPT;
    bool inTag = (when == XML_IN_TAG);
    const char *name = eventIn->getName(x3d);
    if (when == XML_IS) {
        const char *isName = searchIsName(i, EL_EVENT_IN); 
        if (isName)
            RET_ONERROR( writeXmlIs(f, indent, name, isName) )
    } else if (inTag && isScript) {
            return 0;
    } else if (isScript) {
        int flags = _scene->getWriteFlags(); 
        RET_ONERROR( eventIn->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    } else if (eventName) {
        RET_ONERROR( mywritestr(f, name) )
        RET_ONERROR( mywritestr(f, "\n") )
        TheApp->incSelectionLinenumber();
    }
    return(0);
}


int
NodeData::writeEventInStr(int f)
{
    if (_scene->isX3d())
        RET_ONERROR( mywritestr(f, "inputOnly") )
    else
        RET_ONERROR( mywritestr(f, "eventIn") )
    return 0;
}

int
NodeData::writeEventOutStr(int f)
{
    if (_scene->isX3d())
        RET_ONERROR( mywritestr(f, "outputOnly") )
    else
        RET_ONERROR( mywritestr(f, "eventOut") )
    return 0;
}

int
NodeData::writeFieldStr(int f)
{
    if (_scene->isX3d())
        RET_ONERROR( mywritestr(f, "initializeOnly") )
    else
        RET_ONERROR( mywritestr(f, "field") )
    return 0;
}

int
NodeData::writeExposedFieldStr(int f)
{
    if (_scene->isX3d())
        RET_ONERROR( mywritestr(f, "inputOutput") )
    else
        RET_ONERROR( mywritestr(f, "exposedField") )
    return 0;
}


int 
NodeData::writeEventOut(int f, int indent, int i, bool eventName)
{
    if (!_proto) return(0);

    bool x3d = _scene->isX3dv();

    EventOut *eventOut = _proto->getEventOut(i);
    const char *name = eventOut->getName(x3d);
    const char *isName = searchIsName(i, EL_EVENT_OUT); 
    if (isName)
        RET_ONERROR( writeIs(f, indent, name, isName) )
    else if (eventName) {
        RET_ONERROR( mywritestr(f, name) )
        RET_ONERROR( mywritestr(f, "\n") )
        TheApp->incSelectionLinenumber();
    }
    return(0);
}

int 
NodeData::writeXmlEventOut(int f, int indent, int i, int when, bool eventName)
{
    if (!_proto) return(0);

    bool x3d = _scene->isX3dv();

    EventOut *eventOut = _proto->getEventOut(i);
    bool isScript = eventOut->getFlags() & FF_IN_SCRIPT;
    bool inTag = (when == XML_IN_TAG);
    const char *name = eventOut->getName(x3d);
    if (when == XML_IS) {
        const char *isName = searchIsName(i, EL_EVENT_OUT); 
        if (isName)
            RET_ONERROR( writeXmlIs(f, indent, name, isName) )
    } else if (inTag && isScript) {
            return 0;
    } else if (isScript) {
        int flags = _scene->getWriteFlags(); 
        RET_ONERROR( eventOut->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    } else if (eventName) {
        RET_ONERROR( mywritestr(f, name) )
        RET_ONERROR( mywritestr(f, "\n") )
        TheApp->incSelectionLinenumber();
    }
    return(0);
}

int 
NodeData::writeRoutes(int f, int indent) const
{
    if (!_proto) return(0);

    bool x3d = _scene->isX3dv();

    int i;
    SocketList::Iterator *j;

    for (i = 0; i < _numEventIns; i++) {
        for (j = _inputs[i].first(); j != NULL; j = j->next()) {
            if (j->item().getNode()->getFlag(NODE_FLAG_TOUCHED)) {
                Node *src = j->item().getNode();
                int field = j->item().getField();
                if (_scene->isPureVRML() &&  
                    (matchNodeClass(PARAMETRIC_GEOMETRY_NODE) || 
                     src->matchNodeClass(PARAMETRIC_GEOMETRY_NODE)))
                    continue;
                MyString routeString = _scene->createRouteString(
                      src->getName(x3d), 
                      src->getProto()->getEventOut(field)->getName(x3d),
                      _name, getProto()->getEventIn(i)->getName(x3d));
                _scene->addRouteString(routeString);
            }
        }
    }

    for (i = 0; i < _numEventOuts; i++) {
        for (j = _outputs[i].first(); j != NULL; j = j->next()) {
            if (j->item().getNode()->getFlag(NODE_FLAG_TOUCHED)) {
                Node *dst = j->item().getNode();
                int field = j->item().getField();
                if (_scene->isPureVRML() &&  
                    (matchNodeClass(PARAMETRIC_GEOMETRY_NODE) || 
                     dst->matchNodeClass(PARAMETRIC_GEOMETRY_NODE)))
                    continue;
                MyString routestring = _scene->createRouteString(_name,
                         getProto()->getEventOut(i)->getName(x3d),
                         dst->getName(x3d),
                         dst->getProto()->getEventIn(field)->getName(x3d));
                _scene->addRouteString(routestring);
            }
        }
    }

#ifndef HAVE_ROUTE_AT_END
    if (indent==0)
       RET_ONERROR( _scene->writeRouteStrings(f, indent) )
#endif
    return 0;
}

int         
Node::writeCDataFunctions(int filedes, int languageFlag)
{
    if (_convertedNode != NULL)
        return _convertedNode->writeCDataFunctions(filedes, languageFlag);

    int i;
    if (_numberCDataFunctions > 0) {
        if (languageFlag & MANY_JAVA_CLASSES)
            RET_ONERROR( mywritef(filedes, "class %sScenegraphFunctions%d {\n", 
                                  TheApp->getCPrefix(), 
                                  _scene->getNumDataFunctions()) )
        RET_ONERROR( mywritestr(filedes , "    ") )
        if (languageFlag & MANY_JAVA_CLASSES)
            RET_ONERROR( mywritestr(filedes , "static ") )
        RET_ONERROR( mywritef(filedes , "void data%sFunction%d() {\n",
                              TheApp->getCPrefix(),
                              _scene->increaseNumDataFunctions()) )

        for (i = 0; i < _numberCDataFunctions; i++)
            if (languageFlag & MANY_JAVA_CLASSES) {
                RET_ONERROR( mywritef(filedes , 
                                      "        new %sDataClass%d();\n", 
                                      getVariableName(), i) )
            } else 
                RET_ONERROR( mywritef(filedes , 
                                      "        %sDataFunction%d();\n", 
                                      getVariableName(), i) )
        RET_ONERROR( mywritestr(filedes , "    }\n") )
        if (languageFlag & MANY_JAVA_CLASSES)
            RET_ONERROR( mywritestr(filedes , "}\n") )
    }

    for (i = 0; i < _numFields; i++) {
        Field *field = _proto->getField(i);
        FieldValue *value = _fields[i];

        if (field->getType() == SFNODE) {
            if (value) {
                Node *node = ((SFNode *)value)->getValue();
                if (node && (node != this)) // avoid simple cyclic scenegraph
                    RET_ONERROR( node->writeCDataFunctions(filedes, 
                                                           languageFlag) )
            }
        } else if (field->getType() == MFNODE) {
            if (value) {
                MFNode *nodes = (MFNode *)value;
                for (int i = 0; i < nodes->getSize(); i++) {
                    Node *node = nodes->getValue(i);
                    if (node && (node != this)) //avoid simple cyclic scenegraph
                        RET_ONERROR( node->writeCDataFunctions(filedes, 
                                                               languageFlag) )
                }
            }
        }
    }
    if (hasProtoNodes()) {
        Node *protoRoot = ((NodePROTO *)this)->getProtoRoot();
        RET_ONERROR( protoRoot->writeCDataFunctions(filedes, languageFlag) )
    }
    return 0;
}

int
Node::writeC(int f, int languageFlag)
{
    if (_convertedNode != NULL)
        return _convertedNode->writeC(f, languageFlag);

    if (getType() == VRML_COMMENT)
        return 0;
    if (_proto->isMismatchingProto())
        return 0;   

    // allows several nodetypes to output a warning via inheritance
    writeCWarning();

    bool writeInside = true;
    if (languageFlag & MANY_JAVA_CLASSES)
        if (writeJavaOutsideClass(languageFlag))
            writeInside = false;

    if (languageFlag & C_SOURCE) {
        RET_ONERROR( mywritestr(f, "    ") )
        RET_ONERROR( mywritestr(f, getClassName()) )
        RET_ONERROR( mywritestr(f, "Init(&self->") )
        RET_ONERROR( mywritestr(f, getVariableName()) )
        RET_ONERROR( mywritestr(f, ");\n") )    
    } else if ((writeInside) && (languageFlag & JAVA_SOURCE)) {
        RET_ONERROR( mywritestr(f, "    ") )
        RET_ONERROR( mywritestr(f, "    ") )
        if (languageFlag & MANY_JAVA_CLASSES)
            RET_ONERROR( mywritestr(f, "    ") )
        RET_ONERROR( writeCVariable(f, languageFlag) )    
        RET_ONERROR( mywritestr(f, " = new ") )
        RET_ONERROR( mywritestr(f, getClassName()) )
        RET_ONERROR( mywritestr(f, "();\n") )    
    } 

    if (!(languageFlag & JAVA_SOURCE)) {
        int i;
        for (i = 0; i < _numFields; i++)
            RET_ONERROR( writeCField(f, i, languageFlag, true) )    
        for (i = 0; i < _numFields; i++)
            RET_ONERROR( writeCField(f, i, languageFlag, false) )    
    } 

    if (writeInside) {
        if (languageFlag & JAVA_SOURCE) {       
            RET_ONERROR( mywritestr(f, "    ") )
            if (languageFlag & MANY_JAVA_CLASSES)
                RET_ONERROR( mywritestr(f, "    ") )
        }
        RET_ONERROR( mywritestr(f, "    ") )
        RET_ONERROR( writeCVariable(f, languageFlag) )    
        RET_ONERROR( mywritestr(f, ".m_parent = ") )

        if (hasParent()) {
            if (!(languageFlag & JAVA_SOURCE))        
                RET_ONERROR( mywritestr(f, "&") )    
            RET_ONERROR( getParent()->writeCVariable(f, languageFlag) )    
        } else {
            if (languageFlag & JAVA_SOURCE)
                RET_ONERROR( mywritestr(f, "null") )            
            else 
                RET_ONERROR( mywritestr(f, "NULL") )            
        } 
        RET_ONERROR( mywritestr(f, ";\n") )  

        if (hasProtoNodes()) {
            if (languageFlag & JAVA_SOURCE) {       
                RET_ONERROR( mywritestr(f, "    ") )
                if (languageFlag & MANY_JAVA_CLASSES)
                    RET_ONERROR( mywritestr(f, "    ") )
            }
            Node *protoRoot = ((NodePROTO *)this)->getProtoRoot();
            RET_ONERROR( protoRoot->writeC(f, languageFlag) )

            RET_ONERROR( mywritestr(f, "    ") )
            RET_ONERROR( writeCVariable(f, languageFlag) )    
            RET_ONERROR( mywritestr(f, ".m_protoRoot = ") )
            if (!(languageFlag & JAVA_SOURCE))
                RET_ONERROR( mywritestr(f, "&") )  
            RET_ONERROR( protoRoot->writeCVariable(f, languageFlag) )
            RET_ONERROR( mywritestr(f, ";\n") )  
        }  
    }

    if (languageFlag & C_SOURCE) {
        RET_ONERROR( mywritestr(f, "    self->") )
        RET_ONERROR( mywritestr(f, getVariableName()) )
        RET_ONERROR( mywritestr(f, ".") )
        RET_ONERROR( mywritestr(f, "m_") )
        RET_ONERROR( mywritestr(f, "type = ") )
        RET_ONERROR( mywritef(f, "%d", getType()) )
        RET_ONERROR( mywritestr(f, ";\n") )    
    } 

    return 0;
}

int
Node::writeCDataAsFunctions(int f, int languageFlag)
{
    if (_convertedNode != NULL)
        return _convertedNode->writeCDataAsFunctions(f, languageFlag);

    if (getType() == VRML_COMMENT)
        return 0;
    if (_proto->isMismatchingProto())
        return 0;  

    // do not write multiple declarations for USE'd nodes
    if (getFlag(NODE_FLAG_TOUCHED))
        return 0;
    setFlag(NODE_FLAG_TOUCHED); 

    if (!(languageFlag & JAVA_SOURCE))
        return 0;

    _numberCDataFunctions = 0;

    int i;
    for (i = 0; i < _numFields; i++)
        RET_ONERROR( writeCFieldFunction(f, i, languageFlag, true) )    
    for (i = 0; i < _numFields; i++)
        RET_ONERROR( writeCFieldFunction(f, i, languageFlag, false) )    

    if (hasProtoNodes()) {
        Node *protoRoot = ((NodePROTO *)this)->getProtoRoot();
        RET_ONERROR( protoRoot->writeCDataAsFunctions(f, languageFlag) )    
    }
    return 0;
}

int 
Node::writeCFieldFunction(int f, int i, int languageFlag, bool nodeFlag)
{
    if (_convertedNode)
        return _convertedNode->writeCFieldFunction(f, i, languageFlag, 
                                                   nodeFlag);
    if (i == _proto->metadata_Field())
        return 0;

    Field *field = _proto->getField(i);

    if (_scene->isInvalidElement(field))
        return 0;

    if (nodeFlag)
        if ((field->getType() != SFNODE) && (field->getType() != MFNODE))
            return 0;

    FieldValue *value = _fields[i];
    if (value->writeType(languageFlag)) {
        if (languageFlag & MANY_JAVA_CLASSES) {
            RET_ONERROR( mywritef(f, "    class %sDataClass%d {\n", 
                                  getVariableName(), _numberCDataFunctions,  
                                  (const char*)getClassName()) )    
            RET_ONERROR( mywritef(f, "        public %sDataClass%d() {\n", 
                                  getVariableName(), _numberCDataFunctions) )
        } else 
            RET_ONERROR( mywritef(f, "    void %sDataFunction%d() {\n", 
                                  getVariableName(), _numberCDataFunctions,  
                                  (const char*)getClassName()) )    
        _numberCDataFunctions++; 
        RET_ONERROR( writeCField(f, i, languageFlag, nodeFlag) )
        if (languageFlag & MANY_JAVA_CLASSES)
            RET_ONERROR( mywritestr(f, "        }\n") )    
        RET_ONERROR( mywritestr(f, "    }\n") )    
    } else if (!nodeFlag) {
        // write long array into a series of functions to fight against the
        // java "code too long" (64 KB) problem
        MFieldValue *mvalue = (MFieldValue *)value;
        int javaCodeToLongLimit = 1 << 16;
        int javaSizeOfLine = 8;
        int maxNumberElements = TheApp->GetWrittenElementsPerJavaArray();
        if (maxNumberElements == -1)
            maxNumberElements = javaCodeToLongLimit / mvalue->getStride() / 
                                javaSizeOfLine / 4;
        int numberFunctions = mvalue->getSFSize() / maxNumberElements + 1;
        int offset = 0;
        for (int i = 0; i < numberFunctions; i++) {
            if (languageFlag & MANY_JAVA_CLASSES) {
                RET_ONERROR( mywritef(f, "    class %sDataClass%d {\n", 
                                      getVariableName(), 
                                      _numberCDataFunctions,  
                                      (const char*)getClassName()) )    
                RET_ONERROR( mywritef(f, "        public %sDataClass%d() {\n",
                                      getVariableName(), 
                                      _numberCDataFunctions) )    
            } else
                RET_ONERROR( mywritef(f, "    void %sDataFunction%d() {\n", 
                                      getVariableName(), 
                                      _numberCDataFunctions) )    
            _numberCDataFunctions++; 
            const char *fieldName = field->getName(true); 
            if (i == 0) {
                RET_ONERROR( mywritestr(f, "        ") )
                if (languageFlag & MANY_JAVA_CLASSES)
                    RET_ONERROR( mywritestr(f, "    ") )
                RET_ONERROR( writeCVariable(f, languageFlag) )    
                RET_ONERROR( mywritef(f, ".%s = ",
                                      (const char *)field->getName(true)) )
                int size = mvalue->getSFSize() * mvalue->getStride();
                if (size > 0)
                    RET_ONERROR( mywritef(f, "new %s[%d];\n",
                                          value->getTypeC(languageFlag), size) )
                else 
                    RET_ONERROR( mywritestr(f, "null;\n") )
            }
            
            RET_ONERROR( mywritestr(f, "        ") )
            if (languageFlag & MANY_JAVA_CLASSES)
                RET_ONERROR( mywritestr(f, "    ") )
            RET_ONERROR( mywritestr(f, getClassName()) )
            RET_ONERROR( mywritestr(f, " v = ") )
            RET_ONERROR( writeCVariable(f, languageFlag) )    
            RET_ONERROR( mywritestr(f, ";\n") )

            RET_ONERROR( mvalue->writeJavaLongArray(f, languageFlag,
                  fieldName, offset, maxNumberElements, 
                  TheApp->isWonderlandModuleExport() &&
                  (field->getFlags() & FF_WONDERLAND_ART), _scene->getURL()) )
            if (languageFlag & MANY_JAVA_CLASSES)  
                RET_ONERROR( mywritestr(f, "        }\n") )
            RET_ONERROR( mywritestr(f, "    }\n") )
            offset += maxNumberElements;    
        }
    }

    if (nodeFlag && (field->getType() == SFNODE)) {
        if (value) {
            Node *node = ((SFNode *)value)->getValue();
            if (node && (node != this)) // avoid simple cyclic scenegraph
                 RET_ONERROR( node->writeCDataAsFunctions(f, languageFlag) )
        }
    } else if (nodeFlag && (field->getType() == MFNODE)) {
        if (value) {
            MFNode *nodes = (MFNode *)value;
            for (int i = 0; i < nodes->getSize(); i++) {
                Node *node = nodes->getValue(i);
                if (node && (node != this)) // avoid simple cyclic scenegraph
                     RET_ONERROR(node->writeCDataAsFunctions(f, languageFlag) )
            }
        }
    }
    return 0;
}

int 
Node::writeCField(int f, int i, int languageFlag, bool nodeFlag)
{
    if (!_proto) return(0);

    Field *field = _proto->getField(i);

    if (_scene->isX3d()) {
        if (_proto->avoidElement(field, FF_X3D_ONLY))
            return 0;
    } else
        if (_proto->avoidElement(field, FF_VRML_ONLY))
            return 0;

    FieldValue *value = _fields[i];
    const char *name = field->getName(true);

    if (nodeFlag && (field->getType() == SFNODE)) {
        if (value) {
            Node *node = ((SFNode *)value)->getValue();
            if (node && (node != this)) // avoid simple cyclic scenegraph
                 RET_ONERROR( node->writeC(f, languageFlag) )
        }
    } else if (nodeFlag && (field->getType() == MFNODE)) {
        if (value) {
            MFNode *nodes = (MFNode *)value;
            for (int i = 0; i < nodes->getSize(); i++) {
                Node *node = nodes->getValue(i);
                if (node && (node != this)) // avoid simple cyclic scenegraph
                     RET_ONERROR( node->writeC(f, languageFlag) )
            }
        }
    } else if (!nodeFlag) {
        if (value->isArrayInC()) {
            if (languageFlag & JAVA_SOURCE) {
                RET_ONERROR( mywritestr(f, "    ") )
                if (languageFlag & MANY_JAVA_CLASSES)  
                    RET_ONERROR( mywritestr(f, "    ") )
            }
            RET_ONERROR( mywritestr(f, "    {\n") )
        }
        RET_ONERROR( mywritestr(f, "    ") )
        if (languageFlag & JAVA_SOURCE) {       
            RET_ONERROR( mywritestr(f, "    ") )
            if (languageFlag & MANY_JAVA_CLASSES)  
                RET_ONERROR( mywritestr(f, "    ") )
        }
        if (value->isArrayInC()) {
            if (!(languageFlag & JAVA_SOURCE))
                RET_ONERROR( mywritestr(f, "static ") )
            RET_ONERROR( mywritestr(f, value->getTypeC(languageFlag)) )
            RET_ONERROR( mywritestr(f, " ") )
        } else {
            RET_ONERROR( writeCVariable(f, languageFlag) )    
            RET_ONERROR( mywritestr(f, ".") )
        }
        if (TheApp->isWonderlandModuleExport() &&
            (field->getFlags() & FF_WONDERLAND_ART)) {
                 RET_ONERROR( value->writeCWonderlandArt(f, name, languageFlag) 
                            )
        } else
             RET_ONERROR( value->writeC(f, name, languageFlag) )
        if (value->isArrayInC()) {
            if (languageFlag & JAVA_SOURCE) {
                RET_ONERROR( mywritestr(f, "    ") )
                if (languageFlag & MANY_JAVA_CLASSES)  
                    RET_ONERROR( mywritestr(f, "    ") )
            }
            RET_ONERROR( mywritestr(f, "    ") )
            RET_ONERROR( writeCVariable(f, languageFlag) )    
            RET_ONERROR( mywritestr(f, ".") )
            RET_ONERROR( mywritestr(f, name) )
            RET_ONERROR( mywritestr(f, " = ") )
            bool isNull = false;
            if ((languageFlag & C_SOURCE) || (languageFlag & CC_SOURCE))
                if (value->isMFieldValue()) {
                    MFieldValue *mvalue = (MFieldValue *)value;
                    if (mvalue->getSFSize() == 0)
                        isNull = true;
                }
            if (isNull)
                RET_ONERROR( mywritestr(f, "NULL") )
            else {
                RET_ONERROR( mywritestr(f, "m_") )
                RET_ONERROR( mywritestr(f, name) )
            }
            RET_ONERROR( mywritestr(f, ";\n") )
            if (!(languageFlag & JAVA_SOURCE)) {       
                RET_ONERROR( mywritestr(f, "    ") )
                RET_ONERROR( writeCVariable(f, languageFlag) )
                RET_ONERROR( mywritestr(f, ".") )
                RET_ONERROR( mywritestr(f, name) )
                RET_ONERROR( mywritestr(f, "_length") )
                RET_ONERROR( mywritestr(f, " = ") )
                if (value->isMFieldValue() && 
                    (((MFieldValue *)value)->getSFSize() == 0)) {
                    RET_ONERROR( mywritestr(f, "0") )
                } else {
                    RET_ONERROR( mywritestr(f, "sizeof(") )
                    RET_ONERROR( mywritestr(f, "m_") )
                    RET_ONERROR( mywritestr(f, name) )
                    RET_ONERROR( mywritestr(f, ") / sizeof(") )
                    RET_ONERROR( mywritestr(f, value->getTypeC(languageFlag)) )
                    RET_ONERROR( mywritestr(f, ")") )
                }
                RET_ONERROR( mywritestr(f, ";\n") )
            }
            if (languageFlag & JAVA_SOURCE) {
                RET_ONERROR( mywritestr(f, "    ") )
                if (languageFlag & MANY_JAVA_CLASSES)  
                    RET_ONERROR( mywritestr(f, "    ") )
            }
            RET_ONERROR( mywritestr(f, "    }\n") )
        }
    }
    return 0;
}

int
Node::writeCVariable(int f, int languageFlag)
{
    if (languageFlag & C_SOURCE)
        RET_ONERROR( mywritestr(f, "self->") )
    if (languageFlag & MANY_JAVA_CLASSES) {
        if (needExtraJavaClass())
            RET_ONERROR( mywritef(f, "%s%s.", TheApp->getCPrefix(),
                                  getVariableName()) )
        else if (hasName() || (_scene->getRoot() == this))
            RET_ONERROR( mywritef(f, "%sSceneGraph.", TheApp->getCPrefix(),
                                  getVariableName()) )
    }
    RET_ONERROR( mywritestr(f, getVariableName()) )
    return 0;
}

int
NodeData::lookupEventIn(const MyString &name, bool x3d) const
{
    return _proto ? _proto->lookupEventIn(name, x3d) : INVALID_INDEX;
}

int
NodeData::lookupEventOut(const MyString &name, bool x3d) const
{
    return _proto ? _proto->lookupEventOut(name, x3d) : INVALID_INDEX;
}

MyString
NodeData::newEventName(int typeEnum, bool out)
{
    bool x3d = _scene->isX3d();
    char name[1024];
    MyString eventName = "";
    const char *typestr = typeEnumToString(typeEnum);
    if (typestr[0] == 'M')
        eventName += "m";
    for (int i = 2; i < strlen(typestr); i++)
        eventName += tolower(typestr[i]);
    int counter = 0;
    bool foundflag;
    do {
        foundflag = false;
        counter++;
        const char *format = "%d_in";
        if (out)
            format = "%d_out";
        mysnprintf(name, 1023, (const char *)format, counter);

        int numberEvents = 0;
        if (out)
            numberEvents = _proto->getNumEventOuts();
        else
            numberEvents = _proto->getNumEventIns();
        for (int i = 0; i < numberEvents; i++) {
            const char *oldName;
            if (out)
               oldName = (const char*) _proto->getEventOut(i)->getName(x3d);
            else 
               oldName = (const char*) _proto->getEventIn(i)->getName(x3d);
            MyString cmpName = "";
            cmpName += eventName;
            cmpName += name; 
            if (strcmp(oldName, (const char*)cmpName) == 0)
                foundflag = true;
        }
    } while (foundflag == true);
    eventName += name;
    return eventName;
}

void
NodeData::addInput(int eventIn, Node *src, int eventOut)
{
    if (eventIn >= _numEventIns)
        if (isDynamicFieldsNode()) {
            int typeEnum = src->getProto()->getEventOut(eventOut)->getType();
            ((NodeScript *)this)->addEventIn(typeEnum, 
                                             newEventName(typeEnum, false));
            update();
            NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0);
            _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, 
                                (Hint*) hint);
        }
    _inputs[eventIn].append(RouteSocket(src, eventOut));
}

void
NodeData::addOutput(int eventOut, Node *dst, int eventIn)
{
    if (eventOut >= _numEventOuts)
        if (getType() == VRML_SCRIPT) {
            int typeEnum = dst->getProto()->getEventIn(eventIn)->getType();
            ((NodeScript *)this)->addEventOut(typeEnum, 
                                              newEventName(typeEnum, true));
            update();
            NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0);
            _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, 
                                (Hint*) hint);
        }
    _outputs[eventOut].append(RouteSocket(dst, eventIn));
}

void
NodeData::removeInput(int eventIn, Node *src, int eventOut)
{
    SocketList::Iterator *j = _inputs[eventIn].find(RouteSocket(src, eventOut));
    if (j) 
        _inputs[eventIn].remove(j);
}

void
NodeData::removeOutput(int eventOut, Node *dst, int eventIn)
{
    SocketList::Iterator *j = _outputs[eventOut].find(RouteSocket(dst, 
                                                                  eventIn));
    if (j)
        _outputs[eventOut].remove(j);
}

void
NodeData::update()
{
    // used by Script to update its fields and
    // used by shapes to redraw after a change of a MF-field
}

void
NodeData::reInit()
{
    // used to reinitialise private data of a "copy"-ed node
    // e.g. to reinitialise mesh data of some geometric shapes
}


void
Node::addParent(Node *parent, int field)
{
    for (int i = 0; i < _parents.size(); i++)
        if ((_parents[i]._node == parent) && (_parents[i]._field == field)) {
            _geometricParentIndex = i;
            return; // parent already set
        }
    _parents.append(Parent(parent, field, this));
    _geometricParentIndex = _parents.size() - 1;
}

void
Node::removeParent(void)
{
    if (_geometricParentIndex != -1) {
        for (int i = _geometricParentIndex + 1; i < _parents.size(); i++)
            _parents[i]._self->_geometricParentIndex--;
        _parents.remove(_geometricParentIndex);
        _geometricParentIndex = -1;
    }
}


int
NodeData::findChild(Node *child, int field) const
{
    assert(field >= 0 && field < _numFields);

    FieldValue *value = _fields[field];

    if (value->getType() == SFNODE) {
        return (((SFNode *) value)->getValue() == child) ? 0 : -1;
    } else if (value->getType() == MFNODE) {
        NodeList *list = ((MFNode *) value)->getValues();
        for (int i = 0; i < list->size(); i++) {
            if (list->get(i) == child) return i;
        }
        return -1;
    } else {
        return -1;
    }
}

bool
Node::hasAncestor(Node *node) const
{
    if (this != _scene->getRoot()) {
        if (hasParent()) {
            Node *parent = getParent();
            if (parent == node || parent->hasAncestor(node)) 
                return true;
        }  
    }
    return false;
}

bool 
NodeData::checkValidX3d(Element *field)
{
    if (_scene != NULL)
        if (_scene->isX3d()) {
            if (field->getFlags() & FF_VRML_ONLY)
                return false;
        } else {
            if (field->getFlags() & FF_X3D_ONLY)
                return false;
        }
    return true;
}

int
NodeData::findValidFieldType(int childType)
{
    int match = -1;
    for (int field = 0; field < _numFields; field++) {
        if (validChildType(field, childType)) {
            if (match != -1) {
                // ambiguous
                return - 1; 
            }
            match = field;
        }
    }
    return match;
}

int
NodeData::findFirstValidFieldType(int childType)
{
    for (int field = 0; field < _numFields; field++) {
        if (validChildType(field, childType)) {
            return field;
        }
    }
    return -1;
}

int
NodeData::findValidField(Node *child)
{
    int ret = findValidFieldType(child->getNodeClass());
    if (ret == -1)
        ret = findValidFieldType(child->getType());
    return ret;
}

bool
NodeData::validChild(int field, Node *child)
{
    return validChildType(field, child->getNodeClass());
}

bool
NodeData::validChildType(int field, int childType)
{
    const unsigned int selfMask = ~NOT_SELF_NODE;
    if (field < 0 || field >= _numFields) return false;

    Field *def = _proto->getField(field);

    // SFNode field already in use ?
    if ((def->getType() == SFNODE) && 
        (((SFNode *) _fields[field])->getValue() != NULL))
        return false;

    if ((def->getType() == SFNODE) || (def->getType() == MFNODE)) {
        int nodeType = def->getNodeType();

        if (childType & NOT_SELF_NODE) {
            int bits = ::getMaskedNodeClass(nodeType);
            if (bits == 0) {
               bits = nodeType & (~NOT_SELF_NODE);
               if (bits & childType)
                   return false;
            } else
               if (bits & childType)
                   return false;
        }
        if (nodeType == ANY_NODE) {
            return checkValidX3d(def);
        } else if ((::getMaskedNodeClass(childType) != 0) &&
                   (::getMaskedNodeClass(childType) == 
                    ::getMaskedNodeClass(nodeType))) {
            return checkValidX3d(def);
        } else if (isClassType(childType) && 
                   ::matchNodeClass(nodeType, childType)) {
            return checkValidX3d(def);
        } else
           return false;
    } else {
        return false;
    }
}

void
NodeData::setFlagRec(int flag)
{
    setFlag(flag);

    for (int i = 0; i < _numFields; i++) {
        if (_fields[i]->getType() == MFNODE) {
            ((MFNode *) _fields[i])->getValues()->setFlag(flag);
        } else if (_fields[i]->getType() == SFNODE) {
            SFNode *value = (SFNode *) _fields[i];
            if (value->getValue()) value->getValue()->setFlagRec(flag);
        }
    }
}

void
NodeData::clearFlagRec(int flag)
{
    setFlag(flag);

    for (int i = 0; i < _numFields; i++) {
        if (_fields[i]->getType() == MFNODE) {
            ((MFNode *) _fields[i])->getValues()->clearFlag(flag);
        } else if (_fields[i]->getType() == SFNODE) {
            SFNode *value = (SFNode *) _fields[i];
            if (value->getValue()) value->getValue()->clearFlagRec(flag);
        }
    }
}

void
NodeData::sendEvent(int eventOut, double timestamp, FieldValue *value)
{
    assert(eventOut >= 0 && eventOut <= _numEventOuts);

    // handle IS
    bool noIs = true;
    EventOut *evOut = _proto->getEventOut(eventOut);
    if (evOut && (evOut->getFlags() & FF_IS))
        for (int i = 0; i < evOut->getNumIs(); i++)
            if (evOut->getFlags() & EOF_IS_HIDDEN) {
                noIs = false;
                Node *isNode = getIsNode(evOut->getIsNodeIndex(i));
                isNode->sendEvent(evOut->getIsField(i), timestamp, value);
            }

    if (noIs) {

        value->ref();

        SocketList::Iterator    *i;

        for (i = _outputs[eventOut].first(); i != NULL; i = i->next()) {
            RouteSocket s = i->item();
            s.getNode()->receiveEvent(s.getField(), timestamp, value);
        }

        value->unref();
    }
}

void
NodeData::receiveEvent(int eventIn, double timestamp, FieldValue *value)
{
    if (TheApp->getDemoMode()) {
        if ((getType() == VRML_VIEWPOINT) && !TheApp->timeOut())
            return;
    }

    // check to see if this eventIn is part of an exposedField or
    // conntected to a normal field

    int field = -1;
    ExposedField *e = _proto->getEventIn(eventIn)->getExposedField();

    if (e) {
        field = e->getField();
        eventIn = e->getEventIn();
    } else
        field = _proto->getEventIn(eventIn)->getField();

    // handle IS
    EventIn *evIn = _proto->getEventIn(eventIn);
    if (evIn && (evIn->getFlags() & FF_IS))
        for (int i = 0; i < evIn->getNumIs(); i++) {
            Node *isNode = getIsNode(evIn->getIsNodeIndex(i));
            isNode->receiveEvent(evIn->getIsField(i), timestamp, value);
        }
    else {
        if (field != -1) {
            // set the appropriate field
            setField(field, value);
            _scene->OnFieldChange((Node*)this, field);

        // fire off an event here?
        }
    }        
}

// compare content
bool
NodeData::isEqual(Node* node)
{
    if (_identifier==node->_identifier)
       return true;
    else
       return false;
}

bool
NodeData::hasFieldFlag(int flag)
{
    for (int field = 0; field < _numFields; field++) {
        Field *def = _proto->getField(field);
        if (def->getFlags() & FF_URL)
            return true;
    }
    return false;
}

bool
NodeData::hasRoute(SocketList socketlist)
{
   if (socketlist.first() == NULL) 
      return false;
   else
      return true;
}

Path *
Node::getPath() const
{

    int len = 0;
    const Node *node, *root = _scene->getRoot();

    for (node = this; node->hasParent(); node = node->getParent())
        len += 2;

    int *list = new int[len];

    int i = len - 1;
    
    for (node = this; node->hasParentOrProtoParent(); 
         node = node->getParentOrProtoParent()) {
        Node *parent = node->getParentOrProtoParent();
        int field = node->getParentFieldOrProtoParentField();
        FieldValue *value = parent->getField(field);
        if (value->getType() == MFNODE) {
            list[i--] = ((MFNode *) value)->getValues()->find((Node *) node);
        } else if (value->getType() == SFNODE)  {
            list[i--] = 0;
        } else {
            assert(0);
        }
        list[i--] = field;
    }

    Path *path = new Path(list, len, _scene);
    delete [] list;
    list = NULL;
    return path;
}

bool
Node::isInScene(Scene* scene) const
{
    if (scene != _scene) 
        return false;
    if (scene == NULL)
        return false;
    if (this == _scene->getRoot()) 
        return true;
    if (((NodeData *)this)->isInsideProto()) {
        Node *node = ((NodeData *)this)->getNodePROTO();
        if (node)
            return node->isInScene(scene);
        else
            return false;
    }
    if (!this->hasParent())
        return false;
    if (this->getParent()->isInScene(scene))
        return true;
    return false;
}

bool 
Node::supportAnimation(void)
{
    bool x3d = _scene->isX3d();
    Proto *proto = getProto();
    for (int i = 0; i < proto->getNumEventIns(); i++) {
        int type = proto->getEventIn(i)->getType();
        if (x3d) {
            if (proto->getEventIn(i)->getFlags() & FF_VRML_ONLY)
                continue;
        } else
            if (proto->getEventIn(i)->getFlags() & FF_X3D_ONLY)
                continue;

        if (typeDefaultValue(type)->supportAnimation(x3d))
            return true;
    }
    return false;
}


bool 
Node::supportInteraction(void)
{
    Proto *proto = getProto();
    for (int i = 0; i < proto->getNumEventIns(); i++) {
        int type = proto->getEventIn(i)->getType();
        if (typeDefaultValue(type)->supportInteraction())
            return true;
    }
    return false;
}

bool
Node::isInvalidChild(void)
{
    if (this == _scene->getRoot())
        return true;
    if (isInvalidChildNode() &&
        (getParent()->getProto()->getField(getParentField())->getType() 
         == MFNODE)
       )
        return true;
    return false;
}

Vec3f               
Node::getMinBoundingBox(void)
{
   Vec3f ret(0, 0, 0);
   return ret;
}

Vec3f               
Node::getMaxBoundingBox(void)
{
   Vec3f ret(0, 0, 0);
   return ret;
}

void 
Node::appendComment(Node *node)
{ 
    _commentsList->append(node); 
}

void Node::appendTo(NodeList* nodelist)
{
    for (int i = 0;i < _commentsList->size(); i++)
       nodelist->append((*_commentsList)[i]);
    nodelist->append(this);
    _commentsList->resize(0);
}

void                
Node::doWithParents(DoWithNodeCallback callback, void *data,
                    bool searchInRest, bool callSelf)
{
    for (int i = 0; i < _parents.size(); i++) {
        bool call = true;
        if (i == _geometricParentIndex)
            if (!callSelf)
                call = false;
        if (call) 
            if (!callback(_parents[i]._node, data))
                if (!searchInRest)
                    break; 
    }
}

void
Node::doWithSiblings(DoWithNodeCallback callback, void *data,
                     bool searchInRest, bool callSelf)
{
    if (hasParent()) {
        Node *parent = getParent();
        int parentField = getParentField();
        FieldValue *parentValue = parent->getField(parentField);
        if (parentValue->getType() == MFNODE) {
            MFNode *value = (MFNode *)parentValue;
            for (int i = 0; i < value->getSize(); i++) {
                Node *sibling = value->getValue(i);
                if (sibling != NULL) {
                    bool call = true;
                    if (sibling == this)
                        if (!callSelf)
                            call = false;
                    if (call)    
                        if (!callback(sibling, data))
                            if (!searchInRest)
                                break; 
                }
            }      
        }
    }
}

bool Node::doWithBranch(DoWithNodeCallback callback, void *data, 
                        bool searchInRest, bool skipBranch, bool skipProto,
                        bool callSelf)
{
    bool searchOn = true;
    // search in current node itself
    if (callSelf)
        searchOn = callback(this, data);
    if (searchOn && (!skipProto) && hasProtoNodes())
        return ((NodePROTO *)this)->getProtoRoot()->doWithBranch(callback,
                                                                 data, false);
    if (searchOn) {
        // search in children of of current node
        for (int i = 0; i < _proto->getNumFields(); i++)
            if (_proto->getField(i)->getType() == SFNODE) {
                Node *child = ((SFNode *) getField(i))->getValue();
                if (child) {
                    if (child == this) { 
                        swDebugf("%s %s: %s",
                                 "Warning: simple cyclic scenegraph: USE",
                                 (const char *)getName(true),
                                 "invalid VRML/X3D file...\n");
                        return false; 
                    }
                    if (!child->doWithBranch(callback, data, false))
                        if (skipBranch)
                            continue;
                        else
                            return false;
                }
            } else if (_proto->getField(i)->getType() == MFNODE) {
                NodeList *childList = ((MFNode *) getField(i))->getValues();
                if (childList) {
                    for (int j = 0; j < childList->size(); j++) {
                        Node *child = childList->get(j);
                        if (child == this) {
                            swDebugf("%s %s %s: %s",
                                     "Warning: simple cyclic scenegraph: USE",
                                     (const char *)getName(true),
                                     "invalid VRML/X3D file...\n");
                            return false; 
                        }
                        if (child) 
                            if (!child->doWithBranch(callback, data, false))
                                if (skipBranch)
                                    continue;
                                else
                                    return false;       
                    }
                }
            }
        if (searchInRest) {
            // search in next children of current parent
            if (this != _scene->getRoot())
                if (hasParent() && isInScene(_scene)) {
                    Node *parent = getParent();
                    FieldValue *selfField = parent->getField(getParentField()); 
                    if ((selfField != NULL) && 
                        (selfField->getType() == MFNODE)) {
                        int index = parent->findChild(this, getParentField());
                        MFNode *mfNode = (MFNode *)selfField;
                        NodeList *childList = mfNode->getValues();
                        if (childList)
                            for (int j = index + 1; j < childList->size(); j++){
                                Node *child = childList->get(j);
                                if (child) 
                                    if (!child->doWithBranch(callback, data, 
                                                             false))
                                        if (skipBranch)
                                            continue;
                                        else
                                            return false;       
                            }
                    }
                }
        }
    }
    return searchOn;
}

bool
Node::doWithSimilarBranch(DoWithSimilarBranchCallback callback, 
                          Node *similarNode, void *data)
{
    if (!callback(this, similarNode, data))
        return false;
    if (_numFields != similarNode->getProto()->getNumFields())
        return false;
    for (int i = 0; i < _numFields; i++) {
        if (_fields[i]->getType() == SFNODE) {
            if (similarNode->getField(i)->getType() != SFNODE)
                return false;
            Node *child = ((SFNode *) _fields[i])->getValue();
            Node *node = ((SFNode *) similarNode->getField(i))->getValue(); 
            if (child && node) { 
                if (!child->doWithSimilarBranch(callback, node, data))
                    return false;
            } else if (child || node)
                return false;
        } else if (_fields[i]->getType() == MFNODE) {
            if (similarNode->getField(i)->getType() != MFNODE)
                return false;
            NodeList *childList = ((MFNode *) _fields[i])->getValues();
            NodeList *nodeList = ((MFNode *) 
                                  similarNode->getField(i))->getValues(); 
            if (childList && nodeList) {
                if (childList->size() != nodeList->size())
                    return false;
                for (int j = 0; j < childList->size(); j++) {
                    Node *child = childList->get(j);
                    Node *node = nodeList->get(j);
                    if (child && node) {
                        if (!child->doWithSimilarBranch(callback, node, data)) 
                            return false;
                    } else if (child || node)
                        return false;
                }
            } else if ((childList != NULL) || (nodeList != NULL))
                return false;
        }
    }
    return true;   
}

void
Node::copyChildrenTo(Node *copyedNode)
{
    for (int i = 0; i < _numFields; i++) {
        if (_fields[i]->getType() == SFNODE) {
            Node *child = ((SFNode *) _fields[i])->getValue();
            if (child) {
                Node *copyChild = child->copy();
                copyChild->ref();
                copyedNode->setField(i, new SFNode(copyChild));
                child->copyChildrenTo(copyChild);
            }
        } else if (_fields[i]->getType() == MFNODE) {
            NodeList *childList = ((MFNode *) _fields[i])->getValues();
            if (childList) {
                MFNode *field = new MFNode((MFNode *)_fields[i]);
                if (field) {
                    copyedNode->setField(i, field);
                    MFNode *mfnode = (MFNode *) copyedNode->getField(i);
                    for (int j = 0; j < childList->size(); j++) {
                        Node *copyChild = mfnode->getValue(j);
                        if (copyChild && childList->get(j)) {
                            childList->get(j)->ref();
                            childList->get(j)->copyChildrenTo(copyChild);
                        }
                    }
                }
            }
        }
    }   
}

void
Node::doWithAllElements(DoWithAllElementsCallback callback, void *data)
{
    int i = 0;
    for (i = 0; i < _proto->getNumFields(); i++)
        callback(_proto->getField(i), data);
    for (i = 0; i < _proto->getNumEventIns(); i++)
        callback(_proto->getEventIn(i), data);
    for (i = 0; i < _proto->getNumEventOuts(); i++)
        callback(_proto->getEventOut(i), data);
    for (i = 0; i < _proto->getNumExposedFields(); i++)
        callback(_proto->getExposedField(i), data);
}

void
NodeData::removeChildren(void) 
{
    for (int i = 0; i < _numFields; i++)
        if (_fields[i]->getType() == SFNODE)
            setField(i, new SFNode(NULL));
        else if (_fields[i]->getType() == MFNODE)
            setField(i, new MFNode());
}

void
NodeData::handleIs(void)
{
    // PROTO initialisation ready ?
    if (_nodePROTO == NULL)
        return;

    bool x3d = _scene->isX3d();

    // handle IS
    int i;
    for (i = 0; i < _proto->getNumExposedFields(); i++) {
        ExposedField *field = _proto->getExposedField(i);
        if (field->getFlags() & FF_IS)
            for (int j = 0; j < field->getNumIs(); j++) {
                Node *isNode = getIsNode(field->getIsNodeIndex(j));
                FieldValue *value = field->getValue()->copy();
                isNode->setField(field->getIsField(j), value);
            }
    }
    for (i = 0; i < _proto->getNumFields(); i++) {
        Field *field = _proto->getField(i);
        if (field->getFlags() & FF_IS)
            for (int j = 0; j < field->getNumIs(); j++) {
                Node *isNode = getIsNode(field->getIsNodeIndex(j));
                FieldValue *value = field->getDefault(x3d)->copy();
                isNode->setField(field->getIsField(j), value);
            }                                 
    }
    if (isPROTO())
        for (i = 0; i < _proto->getNumEventOuts(); i++) {
            EventOut *eventOut = _proto->getEventOut(i);
            if (eventOut->getFlags() & FF_IS)
               for (int j = 0; j < eventOut->getNumIs(); j++)
                   if (eventOut->getFlags() & EOF_IS) {
                       Node *isNode = getIsNode(eventOut->getIsNodeIndex(j)); 
                       Proto *proto = isNode->getProto();
                       int evOut = eventOut->getIsField(j);
                       EventOut *tEventOut = proto->getEventOut(evOut);
                       tEventOut->addIs((Node *)this, i, EL_EVENT_OUT, NULL, -1,
                                        EOF_IS_HIDDEN);
                   }
        }
}

Node *
NodeData::getIsNode(int nodeIndex)
{
    NodePROTO *nodeProto = (NodePROTO *)this;
    Node *nodeInPROTO = nodeProto->getIsNode(nodeIndex);
    if (nodeInPROTO)
        return nodeInPROTO;
    return NULL;
}

bool                
NodeData::isDefault(int field) const
{
    bool x3d = _scene->isX3d();
    return _fields[field]->equals(getProto()->getField(field)->getDefault(x3d));
}

bool 
NodeData::hasInputs(void)
{
    for (int j = 0; j < _proto->getNumEventIns(); j++)
        if (getInput(j).size() > 0)
            return true;
    return false;
}

bool 
NodeData::hasOutputs(void)
{
    for (int j = 0; j < _proto->getNumEventOuts(); j++)
        if (getOutput(j).size() > 0)
            return true;
    return false;
}

bool 
NodeData::hasInput(const char* routename) const
{
    bool x3d = _scene->isX3d();
    for (int i = 0; i < _proto->getNumEventIns(); i++)
        if (strcmp(_proto->getEventIn(i)->getName(x3d), routename) == 0)
            if (getInput(i).size() > 0)
                return true;
            else
                return false;
    assert(0);
    return false;
}

bool 
NodeData::hasOutput(const char* routename) const
{
    bool x3d = _scene->isX3d();
    for (int i = 0; i < _proto->getNumEventOuts(); i++)
        if (strcmp(_proto->getEventOut(i)->getName(x3d), routename) == 0)
            if (getOutput(i).size() > 0)
                return true;
            else
                return false;
    assert(0);
    return false;
}

int
NodeData::writeProtoArguments(int f) const
{
    int flags = _scene->getWriteFlags() | WITHOUT_VALUE;
    int i;
    for (i = 0; i < _proto->getNumFields(); i++) {
        if (_scene->isInvalidElement(_proto->getField(i)))
            continue;
        RET_ONERROR( _proto->getField(i)->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    }
    for (i = 0; i < _proto->getNumExposedFields(); i++) {
        if (_scene->isInvalidElement(_proto->getExposedField(i)))
            continue;
        RET_ONERROR( _proto->getExposedField(i)->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    }
    for (i = 0; i < _proto->getNumEventIns(); i++) {
        if (_scene->isInvalidElement(_proto->getEventIn(i)))
            continue;
        RET_ONERROR( _proto->getEventIn(i)->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    }
    for (i = 0; i < _proto->getNumEventOuts(); i++) {
        if (_scene->isInvalidElement(_proto->getEventOut(i)))
            continue;
        RET_ONERROR( _proto->getEventOut(i)->write(f, 1, flags) )
        TheApp->incSelectionLinenumber();
    }
    return 0;
}

bool
NodeData::hasDefault(int flag)
{
    bool x3d = _scene->isX3d();
    for (int i = 0; i < _numFields; i++) {
        Field *field = _proto->getField(i);
        if (field->getFlags() & flag)
            if (!(_fields[i]->equals(field->getDefault(x3d))))
                return false;
    }
    return true;
}

static bool removeConvertedNode(Node *node, void *data)
{
     if (node != NULL)
        node->getScene()->removeNode(node);
    return true;
}     


void              
NodeData::deleteConvertedNode(void)
{
    if (_convertedNode != NULL) {
        _convertedNode->doWithBranch(removeConvertedNode, NULL);
        delete _convertedNode;
       _convertedNode = NULL;
    }
}

bool              
NodeData::needExtraJavaClass(void)
{
    if (getConvertedNode() != NULL)
        return getConvertedNode()->needExtraJavaClass();
    if (hasName() || (_scene->getRoot() == this))
        return false;
    return true;
}

bool
NodeData::writeJavaOutsideClass(int languageFlag)
{
    return ((languageFlag & MANY_JAVA_CLASSES) &&
            (languageFlag & OUTSIDE_JAVA_CLASS));
}

void
NodeData::generateTreeLabel(void)
{
    _treeLabel = "";
    if (TheApp->is4Catt())
        if (isMesh()) {
            if (hasTwoSides()) {
               if (isDoubleSided())
                   _treeLabel += "(2 sides) ";
               else
                   _treeLabel += "(1 side) ";
            } else
               _treeLabel += "(only 1 side) ";
        }     
    if (hasName()) {
        _treeLabel += getName();
        const char *protoName = _proto->getName(_scene->isX3d());
        if (stringncmp(getName(), protoName) != 0) { 
            _treeLabel += " ";
            _treeLabel += protoName;
        }
    } else
        _treeLabel += _proto->getName(_scene->isX3d());
}

Node *
Node::getParentOrProtoParent(void) const
{ 
    Node *parent = getParent();
    if (parent == NULL)
        if (((NodeData *)this)->isInsideProto() && (_nodePROTO != NULL))
            return _nodePROTO->getParent();
    return parent;
}

int
Node::getParentFieldOrProtoParentField(void) const
{ 
    Node *parent = getParent();
    if (parent == NULL)
        if (((NodeData *)this)->isInsideProto() && (_nodePROTO != NULL))
            return _nodePROTO->getParentField();
    return getParentField();
}

int
Node::getParentIndex(void) const
{
    FieldValue *value = getParentFieldValue();
    if (value == NULL)
        return -1;
    if (value->getType() == MFNODE) {
        MFNode *mfValue = (MFNode *)value;
        for (int i = 0; i < mfValue->getSize(); i++) {
            Node *node = mfValue->getValue(i);
            if (node->isEqual((Node *)this))
                if (_geometricParentIndex == node->getGeometricParentIndex())
                    return i;
            }
    }
    return -1;
}

Node *
Node::searchParent(int nodeType) const
{
    for (int i = 0; i < _parents.size(); i++) {
        Node *node = _parents[i]._node;
        if (node->getType() == nodeType)
            return node;
    }
    return getParent();
}

FieldValue *
Node::getParentFieldValue(void) const
{
    if (!hasParent())
        return NULL;
    Node *parent = getParent();
    int parentField = getParentField();
    return parentField == -1 ? NULL : parent->getField(parentField);
}

int
Node::getPrevSiblingIndex(void)
{
    int parentIndex = getParentIndex();
    if (parentIndex > 0)
        return parentIndex - 1;
    return -1;
}

int
Node::getNextSiblingIndex(void)
{
    FieldValue *value = getParentFieldValue();
    if (value == NULL)
        return -1;
    if (value->getType() == MFNODE) {
        MFNode *mfValue = (MFNode *)value;
        for (int i = 0; i < mfValue->getSize() - 1; i++) {
            Node *node = mfValue->getValue(i);
            if (node->isEqual((Node *)this))
                if (_geometricParentIndex == node->getGeometricParentIndex())
                    return i + 1;
            }
    }
    return -1;
}

Node *
Node::getPrevSibling(void)
{
    FieldValue *value = getParentFieldValue();
    if (value == NULL)
        return NULL;
    if (value->getType() == MFNODE) {
        MFNode *mfValue = (MFNode *)value;
        int parentIndex = getParentIndex();
        if (parentIndex > 0)
            return mfValue->getValue(parentIndex - 1);
    }
    return NULL;
}

Node *
Node::getNextSibling(void)
{
    FieldValue *value = getParentFieldValue();
    if (value == NULL)
        return NULL;
    if (value->getType() == MFNODE) {
        MFNode *mfValue = (MFNode *)value;
        for (int i = 0; i < mfValue->getSize() - 1; i++) {
            Node *node = mfValue->getValue(i);
            if (node->isEqual((Node *)this))
                if (_geometricParentIndex == node->getGeometricParentIndex())
                    return mfValue->getValue(i + 1);
            }
    }
    return NULL;
}

void 
NodeData::setDefault(void)
{
    bool x3d = _scene->isX3d();
    for (int i = 0; i < _numFields; i++) {
        Field *field = _proto->getField(i);
        if ((field->getType() != SFNODE) && (field->getType() != MFNODE))
            _scene->setField((Node *)this, i, field->getDefault(x3d)->copy());
    }
}

char*
Node::getExportMaterialName(const char *defaultName)
{
    Node *node = this;   
    // search for DEF name till root of scenegraph
    while (1) {
        if (node->hasName()) {
            char *name = strdup(node->getName());
            if (TheApp->SkipMaterialNameBeforeFirstUnderscore()) {
                char *lastPartOfName = strchr(name, '_');
                if (lastPartOfName) {
                    if (strlen(lastPartOfName + 1) > 0) {
                        name = lastPartOfName + 1;
                    } else if (defaultName != NULL) {                        
                        return buildExportMaterialName(defaultName);
                    }
                }
            } 
            if (TheApp->SkipMaterialNameAfterLastUnderscore()) {
                char *endPointer = (char *)strrchr(name, '_');
                if (endPointer) {
                    endPointer[0] = 0;
                    if ((strlen(name) == 0) && (defaultName != NULL))
                        return buildExportMaterialName(defaultName);
                } 
            }
            return buildExportMaterialName(name);
        } else {
            if (node->hasParent())
                node = node->getParent();
            else {
               if (defaultName != NULL)
                   return buildExportMaterialName(defaultName);
            }           
        }
    }
    return buildExportMaterialName(defaultName);
}

Node *
NodeData::convert2X3d(void) {
    if (getFlag(NODE_FLAG_CONVERTED))
        return NULL;
    setFlag(NODE_FLAG_CONVERTED);
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE)
               ((SFNode *) _fields[i])->convert2X3d();
           else if (_fields[i]->getType() == MFNODE)
               ((MFNode *) _fields[i])->convert2X3d();
    return NULL;
}

Node *
NodeData::convert2Vrml(void) {
    if (getFlag(NODE_FLAG_CONVERTED))
        return NULL;
    setFlag(NODE_FLAG_CONVERTED);
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE)
               ((SFNode *) _fields[i])->convert2Vrml();
           else if (_fields[i]->getType() == MFNODE)
               ((MFNode *) _fields[i])->convert2Vrml();
    return NULL;
}

bool
NodeData::canWriteAc3d(void)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE) {
               Node *node = ((SFNode *)_fields[i])->getValue();
               if (node && (node != this)) // avoid simple cyclic scenegraph
                   return node->canWriteAc3d();
           } else if (_fields[i]->getType() == MFNODE) {
               MFNode *nodes = (MFNode *) _fields[i];
               for (int j = 0; j < nodes->getSize(); j++) {
                   Node *node = nodes->getValue(j);
                   if (node && (node != this)) // avoid simple cyclic scenegraph
                       if (node->canWriteAc3d())
                           return true; 
               }
           }     
    return false; 
}

int
NodeData::writeAc3d(int f, int indent)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE)
               RET_ONERROR( ((SFNode *) _fields[i])->writeAc3d(f, indent) )
           else if (_fields[i]->getType() == MFNODE)
               RET_ONERROR( ((MFNode *) _fields[i])->writeAc3d(f, indent) )
    return 0; 
}

void 
NodeData::handleAc3dMaterial(ac3dMaterialCallback callback, Scene* scene)
{
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE) {
               SFNode *field = (SFNode *) _fields[i];
               field->handleAc3dMaterial(callback, scene);
           } else if (_fields[i]->getType() == MFNODE) {
               MFNode *field = (MFNode *) _fields[i];
               field->handleAc3dMaterial(callback, scene);
           }
}

bool
Node::canWriteCattGeo(void)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE) {
               Node *node = ((SFNode *)_fields[i])->getValue();
               if (node && (node != this)) // avoid simple cyclic scenegraph
                   return node->canWriteCattGeo();
           } else if (_fields[i]->getType() == MFNODE) {
               MFNode *nodes = (MFNode *) _fields[i];
               for (int j = 0; j < nodes->getSize(); j++) {
                   Node *node = nodes->getValue(j);
                   if (node && (node != this)) // avoid simple cyclic scenegraph
                       if (node->canWriteCattGeo())
                           return true; 
               }
           }     
    return false; 
}

int
Node::writeCattGeo(int f, int indent)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE)
               RET_ONERROR( ((SFNode *) _fields[i])->writeCattGeo(f, indent) )
           else if (_fields[i]->getType() == MFNODE)
               RET_ONERROR( ((MFNode *) _fields[i])->writeCattGeo((Node *)this, 
                                                                  f, indent) )
    return 0; 
}

bool
NodeData::canWriteLdrawDat(void)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE) {
               Node *node = ((SFNode *)_fields[i])->getValue();
               if (node && (node != this)) // avoid simple cyclic scenegraph
                   return node->canWriteLdrawDat();
           } else if (_fields[i]->getType() == MFNODE) {
               MFNode *nodes = (MFNode *) _fields[i];
               for (int j = 0; j < nodes->getSize(); j++) {
                   Node *node = nodes->getValue(j);
                   if (node && (node != this)) // avoid simple cyclic scenegraph
                       if (node->canWriteLdrawDat())
                           return true; 
               }
           }     
    return false; 
}

int
NodeData::writeLdrawDat(int f, int indent)
{ 
    for (int i = 0; i < _numFields; i++)
        if (_fields[i] != NULL)
           if (_fields[i]->getType() == SFNODE)
               RET_ONERROR( ((SFNode *) _fields[i])->writeLdrawDat(f, indent) )
           else if (_fields[i]->getType() == MFNODE)
               RET_ONERROR( ((MFNode *) _fields[i])->writeLdrawDat(f, indent) )
    return 0; 
}

