/*         one or more fields failed to be exposed to Python.          */
bool PyFieldAccessHandler::exposeAllFieldsToPython()
{
    for(UInt32 idx = 1; idx <= _pPythonScript->getType().getNumFieldDescs(); ++idx)
    {
        FieldDescriptionBase *desc = _pPythonScript->getType().getFieldDesc(idx);
        assert(desc);

#ifdef OSGPY_DEBUG_CODEGENERATION
        std::string tmp = (desc->isDynamic()) ? "dynamic. Analyzing..." : "static. Skip...";
        std::cout << "Processing field '" << desc->getName() << "' | "
                  << tmp << std::endl;
#endif

        if(desc->isDynamic() == true)
        {
            if(exposeFieldToPython(desc->getName(), desc->getFieldId()) == true)
            {
#ifdef OSGPY_DEBUG_CODEGENERATION
                std::cout << "Successfully exposed field '" << desc->getName()
                          << "'" << std::endl << std::endl;
#endif
            }
            else
            {
                std::cerr << "Error exposing field " << desc->getName()
                          << std::endl;

                _pPyInterpreter->activate();
                _pPyInterpreter->dumpError();
                _pPyInterpreter->clearError();
                _pPyInterpreter->deactivate();

                std::cerr << "The field will not be accessible in Python!"
                          << std::endl << std::endl;
            }
        }
    }

    return true;
}
Action::ResultE
bindEnterDefault(NodeCore *core, Action *action)
{
    AnimBindAction     *bindAct  = dynamic_cast<AnimBindAction *>(action);
    Animation          *anim     = bindAct->getAnim    ();
    const AnimTemplate *animTmpl = bindAct->getTemplate();

    AnimTargetAttachment *targetAtt = getTargetAtt(core);

    FDEBUG(("bindEnterDefault: core [%p] targetAtt [%p]\n",
            core, targetAtt));

    if(targetAtt == NULL)
        return Action::Continue;

    Int32 srcIdx = 0;

    while((srcIdx = animTmpl->findTargetId(targetAtt->getTargetId(),
                                           srcIdx                   )) != -1)
    {
        std::string targetId;
        std::string subTargetId;

        bindAct->splitTargetId(
            animTmpl->getTargetIds(srcIdx), targetId, subTargetId);

        FDEBUG(("bindEnterDefault: targetId [%s] subTargetId [%s]\n",
                targetId.c_str(), subTargetId.c_str()));

        // create the channel

        AnimDataSource      *src     = animTmpl->getSources   (srcIdx);
        AnimChannelUnrecPtr  channel = src     ->createChannel(      );
        anim->editMFChannels()->push_back(channel);

        FieldDescriptionBase *fDesc =
            core->getType().getFieldDesc(subTargetId.c_str());

        if(fDesc == NULL)
        {
            SWARNING << "bindEnterDefault: no field for subTargetId ["
                     << subTargetId << "] found." << std::endl;
            continue;
        }

        // create the blender

        UInt32              fId     = fDesc->getFieldId();
        
        if(targetAtt->getMFBlenders()->size() <= fId)
            targetAtt->editMFBlenders()->resize(fId + 1, NULL);

        AnimBlenderUnrecPtr blender = targetAtt->getBlenders(fId);

        if(blender == NULL)
        {
            blender = src->createBlender();
            (*targetAtt->editMFBlenders())[fId] = blender;
        }

        // connect

        blender->addChannel(channel               );
        blender->connectTo (core, fDesc->getName());

        ++srcIdx;
    }

    return Action::Continue;
}
Action::ResultE
AnimBindAction::bindFields(AttachmentContainer *attCon)
{
    AnimTargetAttachment *targetAtt = getTargetAtt(attCon);

    if(targetAtt == NULL)
        return Action::Continue;

    Animation       *anim  = getAnim();
    DataSourceMapIt  dsIt  = _dsMap.begin();
    DataSourceMapIt  dsEnd = _dsMap.end  ();

    while(dsIt != dsEnd)
    {
        if(dsIt->first.find(targetAtt->getTargetId()) != 0)
        {
            ++dsIt;
            continue;
        }

        std::string targetId;
        std::string subTargetId;

        splitTargetId(dsIt->first, targetId, subTargetId);

        if(targetId != targetAtt->getTargetId())
        {
            ++dsIt;
            continue;
        }

        SINFO << "AnimBindAction::bindFields: binding source '"
              << dsIt->first << "' to '" << targetId << "' - '"
              << subTargetId << "'" << std::endl;

        FieldDescriptionBase *fDesc =
            attCon->getType().getFieldDesc(subTargetId.c_str());

        if(fDesc == NULL)
        {
            SWARNING << "AnimBindAction::bindFields: no Field for "
                     << "subTargetId [" << subTargetId << "] found."
                     << std::endl;
            ++dsIt;
            continue;
        }

        // create channel
        AnimChannelUnrecPtr channel = dsIt->second->createChannel();
        anim->editMFChannels()->push_back(channel);

         // create blender
        UInt32 fId = fDesc->getFieldId();

        if(targetAtt->getMFBlenders()->size() <= fId)
            targetAtt->editMFBlenders()->resize(fId + 1, NULL);

        AnimBlenderUnrecPtr blender = targetAtt->getBlenders(fId);

        if(blender == NULL)
        {
            blender = dsIt->second->createBlender();
            targetAtt->editMFBlenders()->replace(fId, blender);
        }

        // on create all fields are marked as changed - this causes
        // the blender to write to its destination even though
        // it has no valid input data - avoid it by committing before
        // connecting the blender to its dest
        commitChanges();

        blender->addChannel(channel                 );
        blender->connectTo (attCon, fDesc->getName());

        // remove bound data source from map
        DataSourceMapIt eraseIt = dsIt;
        ++dsIt;
        _dsMap.erase(eraseIt);
    }

    if(_dsMap.empty() == true)
    {
        return Action::Quit;
    }
    else
    {
        return Action::Continue;
    }
}