/*
 * Path.cpp
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * 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 "stdafx.h"

#include "Path.h"
#include "Scene.h"
#include "SFNode.h"
#include "MFNode.h"
#include "Proto.h"
#include "Field.h"

Path::Path(const int *path, int len, Scene *scene)
{
    _needExtraUpdateSelection = false;
    Node *node, *parent = NULL;
    int field = -1, parentField = -1;

    _field = -1;
    _path = NULL;
    _len = len;

    node = scene->getRoot();
    parent = node;

    if (len > 0) {
        _path = new int[_len];
        memcpy(_path, path, _len * sizeof(int));
        int insideProtoLen = -1;
        int insideProtoField = -1;
        for (int i = 0; i < _len;) {
            field = path[i++];
            // shorten path for PROTO nodes
            if (node->isInsideProto()) {
                insideProtoLen = i - 2;
                insideProtoField = path[insideProtoLen];
            }
            // shorten path for inlined nodes
            if (node->getType() == VRML_INLINE) {
                 _len = i - 1;
                 _field = field;
                 if (insideProtoLen != -1) {
                     _len = insideProtoLen;
                     _field = insideProtoField;
                 }
                 break;
            }
            if (i < _len) {
                if (path[i] == -1) {
                    _len = i;
                    break;
                }
            } else {
                _field = field;
                if (insideProtoLen != -1) {
                    _len = insideProtoLen;
                    _field = insideProtoField;
                    _needExtraUpdateSelection = true;
                }
                break;
            }
            if (node->getConvertedNode() != NULL)
                node = node->getConvertedNode();
            Node *newNode = getNextNode(node, field, i++);
            if (newNode != NULL) {
                parent = node;
                parentField = field;
                node = newNode;
                _nodes.append(node);
            } else
                break;
        }
    }
    _node = node;
    _parent = parent;
    _parentField = parentField;
}

Path::~Path()
{
    delete [] _path;
    _path = NULL;
}

Node *
Path::getNextNode(Node *node, int field, int i) const
{
    Node* ret = NULL;
    FieldIndex fieldIndex(field);
    FieldValue *value = NULL;
    if (node->isPROTO())
        value = node->getField(fieldIndex);
    else
        value = node->getField(field);
    if (value == NULL)
        return NULL;
    if (value->getType() == SFNODE)
        ret = ((SFNode *) value)->getValue();
    else if (value->getType() == MFNODE) 
        ret = ((MFNode *) value)->getValue(_path[i]);
    else {
        if (i != (_len - 1))
            swDebugf("strange type in path: %s depth %d field %d\n",
                     typeEnumToString(value->getType()), i, field);
//        assert(0);
    }
    return ret;
}

#include "swt.h"

void
Path::dump() const
{
    Scene *scene = _node->getScene();

    int len = _len;

    swDebugf("scene");
    Node *node = scene->getRoot();
    for (int i = 0; i < len;) {
        swDebugf(".%s", (const char *) 
                 node->getProto()->getField(_path[i])->getName(false));
        FieldValue *value = node->getField(_path[i++]);
        if (i >= len) break;
        if (value->getType() == SFNODE) {
            node = ((SFNode *) value)->getValue();  i++;
        } else if (value->getType() == MFNODE) {
            node = ((MFNode *) value)->getValue(_path[i++]);
        }
        if (node) swDebugf(".%s", (const char *) 
                                  node->getProto()->getName(false));
    }
    swDebugf("\n");
}
