/*! Destructor
 */
RemoteAspect::~RemoteAspect(void)
{
    FieldContainerFactoryBase *pFactory = FieldContainerFactory::the();
    IdSetT::iterator           i;

    FieldContainer            *fcPtr = NULL;

    // subRef received field container
    for(i = _receivedFC.begin(); i != _receivedFC.end(); i++)
    {
        fcPtr = pFactory->getContainer(*i);

        if(fcPtr != NULL)
        {
            callDestroyed(fcPtr);

            fcPtr->resolveLinks();
        }
    }

    // subRef received field container
    for(i = _receivedFC.begin(); i != _receivedFC.end(); i++)
    {
        fcPtr = pFactory->getContainer(*i);

        if(fcPtr != NULL)
        {
            do
            {
                fcPtr->subReferenceUnresolved();
                fcPtr = pFactory->getContainer(*i);

            } while(fcPtr != NULL);
        }
    }
}
void RemoteAspect::sendSync(Connection &connection, ChangeList *changeList)
{
    FieldContainerFactoryBase *fcFactory = FieldContainerFactory::the();

    if(_statistics)
    {
        _statistics->getElem(statSyncTime)->start();
    }

    if(!changeList)
    {
        changeList = OSG::Thread::getCurrentChangeList();
    }

    // tell my aspect id
    connection.putValue(_aspectId);

    sendIdMapping(connection);

    ChangeList::ChangedStoreConstIt changedIt  = changeList->beginCreated();
    ChangeList::ChangedStoreConstIt changedEnd = changeList->endCreated  ();

    for(; changedIt != changedEnd; ++changedIt)
    {
        UInt32          localId = (*changedIt)->uiContainerId;
        FieldContainer *fcPtr   = fcFactory->getContainer(localId);

        // fcPtr might be locally destroyed already or
        // cluster local, no need to transmit it
        if((fcPtr  == NULL                                     ) ||
                (0x0000 == (fcPtr->getFieldFlags()->_bNamespaceMask &
                            FCLocal::Cluster                         ))  )
        {
            continue;
        }

        if((*changedIt)->uiEntryDesc == ContainerChangeEntry::Create)
        {
            sendCreated(connection, fcPtr);
        }
    }

    changedIt  = changeList->begin();
    changedEnd = changeList->end  ();

    for(; changedIt != changedEnd; ++changedIt)
    {
        UInt32          localId = (*changedIt)->uiContainerId;
        FieldContainer *fcPtr   = fcFactory->getContainer(localId);

        // fcPtr might be cluster local, no need to transmit it.
        // but we need to transmit subrefs for locally destroyed container
        // so this test is different from the one above!
        if((fcPtr  != NULL                                      )  &&
                (0x0000 == (fcPtr->getFieldFlags()->_bNamespaceMask &
                            FCLocal::Cluster                         ))   )
        {
            continue;
        }

        if((*changedIt)->uiEntryDesc == ContainerChangeEntry::AddReference)
        {
            sendAddRefed(connection, fcPtr, localId);
        }
        else if((*changedIt)->uiEntryDesc == ContainerChangeEntry::SubReference)
        {
            sendSubRefed(connection, fcPtr, localId);
        }
        else if((*changedIt)->uiEntryDesc == ContainerChangeEntry::Change &&
                fcPtr                     != NULL                           )
        {
            sendChanged(connection, fcPtr, (*changedIt)->whichField);
        }
    }

    UInt8 cmd = SYNCENDED;
    connection.putValue(cmd);

#ifndef OSG_REMOTE_ASPECT_SILENT
    SLOG << "Send SYNCENDED" << std::endl;
#endif

    // write buffer
    connection.flush();

    if(_statistics)
    {
        _statistics->getElem(statSyncTime)->stop();
    }
}
void RemoteAspect::receiveSync(Connection &connection, bool applyToChangelist)
{
    bool                              finish    = false;
    UInt8                             cmd;
    FieldContainerFactoryBase        *fcFactory = FieldContainerFactory::the();
    FieldContainerVector              newContainers;
    RemoteAspectFieldContainerMapper  mapper;
    ChangeList                       *pChangeList =
        Thread::getCurrentChangeList();

    if(_statistics)
    {
        _statistics->getElem(statSyncTime)->start();
    }

    connection.selectChannel();
    connection.getValue(_remoteAspectId);

    // register mapper into factory
    mapper._remoteAspect = this;

    fcFactory->setMapper(&mapper);

    do
    {
        connection.getValue(cmd);

        switch(cmd)
        {
        case SYNCENDED:
        {
            finish = true;

#ifndef OSG_REMOTE_ASPECT_SILENT
            SLOG << "Receive SYNCENDED\n";
#endif
        }
        break;

        case NEWTYPE:
        {
            receiveNewType(connection, fcFactory);
        }
        break;

        case CREATED:
        {
            receiveCreated(connection, fcFactory, newContainers);
        }
        break;

        case CHANGED:
        {
            receiveChanged(connection, fcFactory);
        }
        break;

        case ADDREFED:
        {
            receiveAddRefed(connection, fcFactory, pChangeList);
        }
        break;

        case SUBREFED:
        {
            receiveSubRefed(connection, fcFactory, pChangeList);
        }
        break;

        case IDMAPPING:
        {
            receiveIdMapping(connection);
        }
        break;

        default:
        {
            SFATAL << "Unknown tag:" << Int32(cmd) << std::endl;
            throw RemoteSyncError();
        }
        }
    }
    while(!finish);

#ifndef OSG_REMOTE_ASPECT_SILENT
    PLOG << std::flush;
#endif

    pChangeList->commitDelayedSubRefs();

#ifdef OSG_DEBUG
    FieldContainerVector::const_iterator fcIt  = newContainers.begin();
    FieldContainerVector::const_iterator fcEnd = newContainers.end  ();

    for(; fcIt != fcEnd; ++fcIt)
    {
        if((*fcIt)->getRefCount() <= 1)
        {
            SWARNING << "New container type '" << (*fcIt)->getType().getName()
                     << "' local id '" << (*fcIt)->getId()
                     << "' remote id '"
                     << static_cast<UInt32>(_remoteFC[(*fcIt)->getId()])
                     << "' dies because of missing ref counts."
                     << std::endl;
        }
    }
#endif // OSG_DEBUG

    if(applyToChangelist)
    {
        Thread::getCurrentChangeList()->commitChanges(ChangedOrigin::Sync);
    }
    else
    {
        Thread::getCurrentChangeList()->commitChangesAndClear(ChangedOrigin::Sync);
    }

    // unregister mapper into factory
    fcFactory->setMapper(NULL);

    if(_statistics)
    {
        _statistics->getElem(statSyncTime)->stop();
    }
}
OSG_USING_NAMESPACE

/*! \class OSG::SortLastWindow
Cluster rendering configuration for sort first image composition
*/

/*----------------------------- static grouping functions -----------------*/

void SortLastWindow::buildGroups(void)
{
    UInt32            v          = 0;
    DrawableListT     drawables;
    UInt32            groupCount = 0;
    bool              rebuild    = false;

    // check for new nodes.
    FieldContainerFactoryBase *fcFactory = FieldContainerFactory::the();

    FieldContainer *fcPtr = NULL;

    ChangeList::ChangedStoreConstIt createdI;

    ChangeList *changeList = OSG::Thread::getCurrentChangeList();

    for(createdI  = changeList->beginCreated();
        createdI != changeList->endCreated(); 
        createdI++)
    {
        UInt32 uiId = (*createdI)->uiContainerId;

        fcPtr = fcFactory->getContainer(uiId);

        if(fcPtr != NULL && dynamic_cast<Node *>(fcPtr) != NULL)
            rebuild = true;
    }

    // is rebuild neccessary ?
    if(!rebuild && getMFGroupNodes()->size())
        return;

    groupCount = getMFServers()->size32();

    if(getComposer() != NULL)
    {
        groupCount = getComposer()->getUsableServers();
        if(getComposer()->getClientRendering())
            groupCount++;
    }

    // build groups for all viewports

    clearGroupNodes();
    editMFGroupLengths()->clear();

    for(v = 0; v < getMFPort()->size(); ++v)
    {
        Viewport *vp         = getPort(v);
        Node     *root       = vp->getRoot();

        drawables.clear();

        collectDrawables(root, drawables);

        if(drawables.size())
            splitDrawables(drawables, groupCount, false);
    }
}