//
// Inventor 2.0 bug fixes that affect correctness of programs that work with
// Nodekits and Hidden Children.
// 
// The code in this file fixes problems in the following routines:
// SoPath::getLength()
// SoPickedPoint::getMatrix()
// 
// To get the fixes, compile this file into a .o and then link
// the .o before -lInventor_s.  The linker may give a warning.
// This is normal and expected.
//
// SoPath::getLength() bug:
//     SoPath::getLength and SoPath::getTail can return the wrong answer if the 
//     path contains hidden children. This happens if nodes are appended 
//     between subsequent calls to getLength or getTail. The returned value can 
//     be too large or too far down the path. This error should never cause a 
//     core dump because in the worst case returned length will be the full 
//     path length and the returned tail will be the tail of the full path.
//     Note that only getLength() needs to be fixed. getTail() will be fixed
//     automatically, since its error occurs only because it gets the wrong 
//     answer from getLength.
//
// SoPickedPoint::getMatrix bug:
//     SoPickedPoint::getMatrix does a check to see if the given node is the 
//     tail of the picked path.   If it is the tail, it applies an 
//     SoGetMatrixAction to the entire path. If not, it builds a path from the 
//     head down to the given node.
//
//     The method should cast the path to an SoFullPath when looking at the
//     tail, otherwise if there is a nodekit along the path it will be 
//     incorrectly applying the action to the full path.
//
#include 
#include 
#include 
#include 

int
SoPath::getLength() const
{
    // Cast const away...
    SoPath *This = (SoPath *)this;

    // If we aren't sure how many are public, figure it out:
    if (numPublic == -1) {

	int lastPublicIndex = 0;
	if (minNumPublic > 1)
	    lastPublicIndex = minNumPublic - 1;

	// Last test is for the second to last node.
	// If it passes, then lastPublicIndex will be incremented to be the
	// final node, which we don't need to test.

	for (  ; lastPublicIndex < (getFullLength() - 1) ; lastPublicIndex++) {
	    // Children of this node will be private, so stop.
	    if ( ! nodes[lastPublicIndex]->isOfType(SoGroup::getClassTypeId()))
		break;
	}
	This->numPublic = This->minNumPublic = lastPublicIndex + 1;
    }
    return numPublic;
}

void
SoPickedPoint::getMatrix(SoGetMatrixAction *gma, const SoNode *node) const
{
    SoPath *xfPath;

    // Construct a path from the root down to this node. Use the given
    // path if it's the same
    if (node == NULL || node == ((SoFullPath *)path)->getTail())
	xfPath = path;

    else {
	int     index = getNodeIndex(node);
	xfPath = path->copy(0, index + 1);
	xfPath->ref();
    }

    gma->apply(xfPath);

    if (xfPath != path)
	xfPath->unref();
}