/*! Fills this changelist with entries that represent the current state of
    the system starting at the container with the given id.
    Prototypes are skipped unless skipPrototypes is false.

    For every container a 'Create' entry and a 'Change' entry (marking all fields
    as modified) is added and as many 'AddReference' entries as the ref count
    of the container.
 */
void ChangeList::fillFromCurrentState(UInt32 uiFieldContainerId,
                                      bool   skipPrototypes     )
{
    this->clear();

    UInt32 uiNumContainers = 
        FieldContainerFactory::the()->getNumContainers();

    if(uiNumContainers <= uiFieldContainerId)
    {
        return;
    }

    for(UInt32 i = uiFieldContainerId; i < uiNumContainers; ++i)
    {
        FieldContainer *pContainer = 
            FieldContainerFactory::the()->getContainer(i);

        // skip destroyed FC
        if(pContainer == NULL)
          continue;

        // skip prototypes - unless requested
        if(skipPrototypes == true &&
           (pContainer->getType().getPrototype() == pContainer ||
            pContainer->getType().getPrototype() == NULL         ))
        {
            continue;
        }

        this->addCreated(i, TypeTraits<BitVector>::BitsClear);

        for(Int32 j = 0; j < pContainer->getRefCount(); ++j)
            this->addAddRefd(i);

        ContainerChangeEntry *pEntry = this->getNewEntry();

        pEntry->uiEntryDesc   = ContainerChangeEntry::Change;
        pEntry->pFieldFlags   = pContainer->getFieldFlags();
        pEntry->uiContainerId = i;
        pEntry->whichField    = FieldBits::AllFields;
        pEntry->pList         = this;
    }
}
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 ChangeList::doApply(bool bClear)
{
    if(_bReadOnly == true)
    {
        FWARNING(("Read-only changelist, can not apply\n"));
        return;
    }

#ifdef OSG_MT_CPTR_ASPECT
    FieldContainer      *pSrc  = NULL;
    FieldContainer      *pDst  = NULL;

    ChangedStoreConstIt  ccIt  = _createdStore.begin();
    ChangedStoreConstIt  ccEnd = _createdStore.end  ();


    while(ccIt != ccEnd)
    {
        AspectStoreP pHandler =
            FieldContainerFactory::the()->getContainerHandler(
                (*ccIt)->uiContainerId);

        if(pHandler == NULL)
        {
#ifndef SILENT_CPTR
            fprintf(stderr, "Strange handler nil %d %p\n", 
                    (*ccIt)->uiContainerId, 
                    pHandler);

#endif
            ++ccIt;
            continue;
        }

        pSrc = pHandler->getPtr(_uiAspect                 );
        pDst = pHandler->getPtr(Thread::getCurrentAspect());

        if(pSrc == NULL)
        {
#ifndef SILENT_CPTR
            fprintf(stderr, "Strange src nil %d %p\n", 
                    (*ccIt)->uiContainerId, 
                    pSrc);
            
#endif
            ++ccIt;
            continue;
        }

        if(pDst == NULL)
        {
            if(0x0000 == ((*ccIt)->whichField & FCLocal::MTMask))
            {
                pDst = pSrc->getType().createAspectCopy(pSrc,
                                                        (*ccIt)->uiContainerId);

                Thread::getCurrentChangeList()->addCreated(
                    (*ccIt)->uiContainerId, 
                    TypeTraits<BitVector>::BitsClear);

#ifndef SILENT_CPTR
                fprintf(stderr, "Setup store for %d %p \n",
                        (*ccIt)->uiContainerId,
                        pDst);
#endif

                if(pDst != NULL)
                    pDst->setupAspectStore(pHandler);
                
#ifndef SILENT_CPTR
                pHandler->dump();
#endif
            }
        }

        ++ccIt;
    }


    ChangedStoreIt      cIt  = _changedStore.begin();
    ChangedStoreConstIt cEnd = _changedStore.end  ();

#ifndef SILENT_CPTR
    fprintf(stderr, "CL apply %u -> %u\n",
            _uiAspect,
            Thread::getCurrentAspect());
#endif

    BitVector         syncMode = 0;

    AspectOffsetStore oOffsets;

    while(cIt != cEnd)
    {
        AspectStoreP pHandler =
            FieldContainerFactory::the()->getContainerHandler(
                (*cIt)->uiContainerId);

        if(pHandler == NULL)
        {
            ++cIt;
            continue;
        }

        pSrc = pHandler->getPtr(_uiAspect                 );
        pDst = pHandler->getPtr(Thread::getCurrentAspect());


#ifndef SILENT_CPTR
        fprintf(stderr, "process changes for %d %p %s %p %s\n",
                (*cIt)->uiContainerId,
                pSrc,
                pSrc != NULL ? pSrc->getType().getCName() : "null",
                pDst,
                pDst != NULL ? pDst->getType().getCName() : "null");
#endif

        if(pDst == NULL && 
           pSrc != NULL)
        {
            if((pSrc->getFieldFlags()->_bNamespaceMask & FCLocal::MTMask) != 
               TypeTraits<BitVector>::BitsClear             )
            {
                pDst = pSrc->getType().createAspectCopy(pSrc,
                                                        (*cIt)->uiContainerId);
            
                if(pDst != NULL) 
                {
                    Thread::getCurrentChangeList()->addCreated(
                        (*cIt)->uiContainerId, 
                        TypeTraits<BitVector>::BitsClear);

                    pDst->setupAspectStore(pHandler);
                }

#ifndef SILENT_CPTR
                pHandler->dump();
#endif
            }
            else
            {
                ++cIt;
                continue;
            }
        }

#ifndef SILENT_CPTR
        fprintf(stderr, "Xprocess changes for %d %p %s %p %s | %d %d %p\n",
                (*cIt)->uiContainerId,
                pSrc,
                pSrc != NULL ? pSrc->getType().getCName() : "null",
                pDst,
                pDst != NULL ? pDst->getType().getCName() : "null",
                _uiAspect,
                Thread::getCurrentAspect(),
                pHandler);
#endif

        if((*cIt)->uiEntryDesc == ContainerChangeEntry::Change)
        {
            if(pSrc != NULL && pDst != NULL) // be safe for now
            {
                BitVector mask = ((*cIt)->whichField & 
                                  pSrc->getFieldFlags()->_bThreadLocalFlags);

                if(mask != 0x0000)
                {
                    pHandler->fillOffsetArray(oOffsets, pDst);
                   
#ifndef SILENT_CPTR
                    for(UInt32 i = 0; i < ThreadManager::getNumAspects(); ++i)
                    {
                        fprintf(stderr, "offset %d %d\n", i, oOffsets[i]);
                    }
#endif
                    
                    UInt32 uiSInfo =
                        /*uiSyncInfo*/ 0 |
                        (_uiAspect << 24) |
                        (Thread::getCurrentAspect() << 16);
                    
                    pDst->execSyncV(*pSrc,
                                    mask,
                                    oOffsets,
                                    syncMode,
                                    uiSInfo);
                }
                
                if(bClear == true)
                {
                    pSrc->clearChangeEntry(*cIt);
                }
            }
        }
        else if((*cIt)->uiEntryDesc == ContainerChangeEntry::AddReference)
        {
#ifndef SILENT_CPTR
            fprintf(stderr, "Execute add Ref for %d %s\n",
                    (*cIt)->uiContainerId, pDst->getType().getCName());
#endif

            if(pDst != NULL)
                pDst->addReferenceRecorded();
        }
        else if((*cIt)->uiEntryDesc == ContainerChangeEntry::SubReference)// ||
//            (*cIt)->uiEntryDesc == ContainerChangeEntry::DepSubReference)
        {
#ifndef SILENT_CPTR
            fprintf(stderr, "Execute sub Ref for %d %s\n",
                    (*cIt)->uiContainerId, pDst->getType().getCName());
#endif
            
            if(pDst != NULL)
            {
                //pDst->subReferenceRecorded();
                this->addDelayedSubRef<RecordedRefCountPolicy>(pDst);
            }
        }

        ++cIt;
    }

    commitDelayedSubRefs();

    Thread::getCurrentChangeList()->commitDelayedSubRefs();
#endif
}