/*************************************************************************
 *
 *  $RCSfile: treemanager.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2004-11-15 13:37:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "treemanager.hxx"

#ifndef CONFIGMGR_BACKEND_MERGEDDATAPROVIDER_HXX
#include "mergeddataprovider.hxx"
#endif
#ifndef CONFIGMGR_CACHEACCESS_HXX
#include "cacheaccess.hxx"
#endif

#ifndef CONFIGMGR_NODEACCESS_HXX
#include "nodeaccess.hxx"
#endif
#ifndef CONFIGMGR_TREEACCESSOR_HXX
#include "treeaccessor.hxx"
#endif
#ifndef CONFIGMGR_UPDATEACCESSOR_HXX
#include "updateaccessor.hxx"
#endif

#ifndef _COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
#include <com/sun/star/container/NoSuchElementException.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif

#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif

namespace configmgr
{

    namespace uno = ::com::sun::star::uno;
    namespace lang= ::com::sun::star::lang;

    namespace Path = configuration::Path;
    using configuration::Name;
    using configuration::AbsolutePath;
// =========================================================================
static void test_complete(memory::HeapManager & _rDummy)
{ new TreeManager(NULL,_rDummy); }
// =========================================================================

#define MAKEUSTRING( char_array ) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( char_array ) )
// =========================================================================

static inline
AbsolutePath extractModulePath(AbsolutePath const & _aPath)
{
    if (_aPath.getDepth() <= 1) return _aPath;

    Name aModule = _aPath.getModuleName();

    return AbsolutePath::makeModulePath( aModule, AbsolutePath::NoValidate() );
}
// =========================================================================

// disposing
// -------------------------------------------------------------------------
void TreeManager::disposeAll()
{
    CFG_TRACE_INFO("TreeManager: Disposing all data" );
    CacheList::Map aReleaseList;

    {
        osl::MutexGuard aGuard(m_aCacheList.mutex());
        m_aCacheList.swap(aReleaseList);             // move data out of m_aCacheList
    }

    // free all the trees - not exception safe !! (i.e. disposeBroadcastHelper() must not throw)
    for (CacheList::Map::iterator i = aReleaseList.begin(); i != aReleaseList.end(); ++i)
    {
        if (ConfigChangeBroadcastHelper * pHelper = i->second->releaseBroadcaster())
            ConfigChangeBroadcaster::disposeBroadcastHelper(pHelper);
        i->second.clear();
    }
}

// -------------------------------------------------------------------------
void TreeManager::dispose()
{
    CFG_TRACE_INFO("TreeManager: dispoing the treemanager" );

    RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::TreeManager", "jb99855", "configmgr: TreeManager::dispose().");

    BackendCacheRef xBackendCache = maybeGetBackendCache();

    if (xBackendCache.is()) xBackendCache->getNotifier().removeListener(this);

    // cleaning the cache
    disposeAll();

    disposeBackendCache();
}

// -------------------------------------------------------------------------
void TreeManager::disposeOne(RequestOptions const& _aOptions)
{
    CFG_TRACE_INFO("TreeManager: Disposing data and TreeInfo for user '%s' with locale '%s'",
                    OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );

    CacheRef aRemoved = m_aCacheList.remove(_aOptions);

    if (aRemoved.is())
    {
        // got it out of reachability - now dispose/notify without lock
        implDisposeOne(aRemoved, _aOptions);
    }
    else
        CFG_TRACE_INFO_NI("- No affected TreeInfo found" );
}

// -------------------------------------------------------------------------
void TreeManager::disposeUser(RequestOptions const& _aUserOptions)
{
    osl::ClearableMutexGuard aGuard(m_aCacheList.mutex());

    CFG_TRACE_INFO("TreeManager: Disposing data and TreeInfo(s) for user '%s'",
                    OUSTRING2ASCII(_aUserOptions.getEntity()) );

    typedef std::vector< std::pair< RequestOptions, CacheRef > > DisposeList;

    DisposeList aDisposeList;
    // collect the ones to dispose
    {
        OUString sUser = _aUserOptions.getEntity();
        OSL_ASSERT(sUser.getLength());

        // This depends on the fact that Options are sorted (by struct ltOptions)
        // so that all options belonging to one user are together
        // (and that options with only a user set, sort first)

        CacheList::Map aCacheData;
        m_aCacheList.swap(aCacheData);

        // find the lower_bound of all options for the user
        CacheList::Map::iterator const aFirst = aCacheData.lower_bound(_aUserOptions);

        // find the upper_bound of all options for the user (using the lower one)
        CacheList::Map::iterator aLast = aFirst;
        while (aLast != aCacheData.end() && aLast->first.getEntity() == sUser)
        {
            CFG_TRACE_INFO_NI("- Found TreeInfo for locale '%s'", OUSTRING2ASCII(aLast->first.getLocale()) );
            OSL_ASSERT(aLast->second.is());

            if (aLast->second.is())
                aDisposeList.push_back( DisposeList::value_type(aLast->first,aLast->second) );

            ++aLast;
        }

        if (aFirst == aLast)
            CFG_TRACE_INFO_NI("- No affected TreeInfo found" );

        aCacheData.erase(aFirst, aLast);

        // replace the data into the map
        m_aCacheList.swap(aCacheData);
    }

    // got all out of external reach - now dispose/notify without lock
    aGuard.clear();

    for (DisposeList::iterator i = aDisposeList.begin(); i != aDisposeList.end(); ++i)
    {
        if (i->second.is())
            implDisposeOne(i->second, i->first);
    }
}

// -------------------------------------------------------------------------
void TreeManager::implDisposeOne(CacheRef const & _aDisposedCache, RequestOptions const & _aOptions)
{
    OSL_ASSERT(_aDisposedCache.is());
    CFG_TRACE_INFO("Now removing TreeInfo (user '%s' with locale '%s') and broadcaster",
                    OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );

    // to do: release at the backend (?)
    if (ConfigChangeBroadcastHelper * pHelper = _aDisposedCache->releaseBroadcaster())
        ConfigChangeBroadcaster::disposeBroadcastHelper(pHelper);
}

// ConfigChangeBroadcaster
// -------------------------------------------------------------------------
ConfigChangeBroadcastHelper* TreeManager::getBroadcastHelper(RequestOptions const& _aOptions, bool bCreate)
{
    CacheRef aCache =  bCreate  ? this->getCacheAlways(_aOptions)
                                : m_aCacheList.get(_aOptions);

    return aCache.is() ? aCache->getBroadcaster() : NULL;
}


// -------------------------------------------------------------------------
TreeManager::TreeManager(BackendCacheRef const & _xBackend, memory::HeapManager & _rCacheHeapManager)
: m_xCacheController(_xBackend)
, m_aCacheList()
, m_aTemplates(new CacheData(_rCacheHeapManager))
, m_bEnableAsync(true)
{
    OSL_PRECOND(_xBackend.is(),"Trying to create a TreeManager without a backend");

    if (m_xCacheController.is()) m_xCacheController->getNotifier().addListener(this);
}

// -------------------------------------------------------------------------
TreeManager::~TreeManager()
{
}

// -------------------------------------------------------------------------
TreeManager::BackendCacheRef TreeManager::maybeGetBackendCache() CFG_NOTHROW( )
{
    osl::MutexGuard aGuard(m_aCacheControllerMutex);
    BackendCacheRef xResult(m_xCacheController);
    return xResult;
}

// -------------------------------------------------------------------------
TreeManager::BackendCacheRef TreeManager::getCacheLoader() CFG_UNO_THROW_RTE( )
{
    osl::MutexGuard aGuard(m_aCacheControllerMutex);
    if (!m_xCacheController.is())
    {
        OUString sMsg = OUString::createFromAscii("TreeManager: No backend available - tree manager was already disposed.");
        throw com::sun::star::lang::DisposedException(sMsg,NULL);
    }
    BackendCacheRef xResult(m_xCacheController);
    return xResult;
}

// -------------------------------------------------------------------------
void TreeManager::disposeBackendCache() CFG_NOTHROW( )
{
    osl::ClearableMutexGuard aGuard(m_aCacheControllerMutex);
    if (m_xCacheController.is())
    {
        BackendCacheRef xBackendCache(m_xCacheController);
        m_xCacheController.clear();
        aGuard.clear();
        xBackendCache->dispose();
    }
}

// -------------------------------------------------------------------------

memory::HeapManager & TreeManager::getCacheHeapManager() const
{
    return m_aTemplates.get()->getHeapManager();
}
// -------------------------------------------------------------------------

TreeManager::CacheRef TreeManager::getCacheAlways(RequestOptions const & _aOptions)
{
    osl::MutexGuard aGuard( m_aCacheList.mutex() );

    CacheRef aResult = m_aCacheList.get(_aOptions);
    if (!aResult.is())
    {
        CacheRef aNewCache( new Cache(getCacheHeapManager(), ConfigChangeBroadcaster::newBroadcastHelper()) );
        aResult = m_aCacheList.insert(_aOptions,aNewCache);
    }
    return aResult;
}

// -------------------------------------------------------------------------
memory::Segment* TreeManager::getDataSegment(AbsolutePath const& _rAccessor,
                                             const RequestOptions& _aOptions)
{
    CacheRef aCache = m_aCacheList.get(_aOptions);

    OSL_ENSURE(aCache.is(), "No cache data to get segment for");

    if (aCache.is())
        return aCache->getDataSegment(_rAccessor);

    else
        return NULL;
}
// -------------------------------------------------------------------------

data::NodeAccess TreeManager::requestSubtree(AbsolutePath const& aSubtreePath,
                                                const RequestOptions& _aOptions)
                                             CFG_UNO_THROW_ALL(  )
{
    CFG_TRACE_INFO("TreeManager: request for subtree '%s'", OUSTRING2ASCII(aSubtreePath.toString()));

    CacheRef aCache = getCacheAlways(_aOptions);
    OSL_ENSURE(aCache.is(),"TreeManager: Cannot create cache access for loading node");

    data::Accessor aAccessor(NULL);

    if (!aCache->hasModule(aSubtreePath))
    {
        CFG_TRACE_INFO_NI("TreeManager: cache miss. going to load the node");
        backend::ComponentRequest aQuery( aSubtreePath.getModuleName(), _aOptions );

        backend::CacheLocation aLoadedLocation = getCacheLoader()->loadComponent(aQuery);
        if (aLoadedLocation.isNull())
        {
            CFG_TRACE_WARNING_NI("TreeManager: requested component not found");
            throw com::sun::star::container::
                    NoSuchElementException( MAKEUSTRING("Requested component not found"), NULL);
        }

        CFG_TRACE_INFO_NI("TreeManager: attaching loaded cache segment ");

        aAccessor = data::Accessor(aCache->attachDataSegment(aLoadedLocation.segment,aSubtreePath));
        OSL_ENSURE(aAccessor.is(),"Cannot attach to loaded component");
    }
    else
    {
        CFG_TRACE_INFO_NI("TreeManager: found node in cache");
        if (_aOptions.isRefreshEnabled())
        {
             backend::ComponentRequest aRequest( aSubtreePath.getModuleName(), _aOptions );
             getCacheLoader()->refreshComponent(aRequest);
        }

        aAccessor = data::Accessor(aCache->getDataSegment(aSubtreePath));
        OSL_ENSURE(aAccessor.is(),"Cannot get accessor for existing component");

    }

    data::NodeAddress aResultAddress = aCache->acquireNode(aAccessor,aSubtreePath);

    return data::NodeAccess(aAccessor,aResultAddress);
}

// -------------------------------------------------------------------------
void TreeManager::fetchSubtree(AbsolutePath const& aSubtreePath, const RequestOptions&  ) CFG_NOTHROW()
{
    CFG_TRACE_WARNING("TreeManager: Prefetching not implemented. (Request to prefetch component %s.", OUSTRING2ASCII(aSubtreePath.toString()));
}

// -------------------------------------------------------------------------
sal_Bool TreeManager::fetchDefaultData( memory::UpdateAccessor& _aAccessToken,
                                        AbsolutePath const& aSubtreePath,
                                        const RequestOptions& _aOptions
                                      ) CFG_UNO_THROW_ALL(  )
{
    CFG_TRACE_INFO("tree manager: checking the cache for defaults");

    CacheRef aCache = m_aCacheList.get(_aOptions);

    if (!aCache.is())
    {
        OSL_ENSURE(aCache.is(),"TreeManager: Cache access to fetch defaults for does not exist ! Where does the node access come from ?");
        return false;
    }

    if (aCache->hasModuleDefaults(_aAccessToken.accessor(),aSubtreePath))
    {
        CFG_TRACE_INFO_NI("TreeManager: found default data in cache");
        return true;
    }

    AbsolutePath aRequestPath = extractModulePath(aSubtreePath);

    backend::NodeRequest aRequest(aRequestPath,_aOptions);

    backend::NodeResult aDefaults = getCacheLoader()->getDirectDataProvider().getDefaultData( aRequest );

    if (!aDefaults.is())
    {
        CFG_TRACE_INFO_NI("TreeManager: merging loaded defaults into cache");
        return aCache->insertDefaults(_aAccessToken,aDefaults.instance());
    }
    else
    {
        CFG_TRACE_WARNING_NI("TreeManager: cannot load defaults: no data available or not supported");
        return false;
    }
}

// -------------------------------------------------------------------------
std::auto_ptr<ISubtree> TreeManager::requestDefaultData(AbsolutePath const& aSubtreePath,
                                                        const RequestOptions& _aOptions
                                                       ) CFG_UNO_THROW_ALL(  )
{
    // to do: check cache for existing default data (?!)
    CFG_TRACE_INFO_NI("TreeManager: loading default data directly");

    backend::NodeRequest aRequest(aSubtreePath,_aOptions);

    backend::NodeResult aDefaults = getCacheLoader()->getDirectDataProvider().getDefaultData( aRequest );

    return aDefaults.extractDataAndClear();
}

// -------------------------------------------------------------------------
AbsolutePath TreeManager::encodeTemplateLocation(const Name& _rLogicalTemplateName, const Name &_rModule)
{
    using namespace configuration::Path;

//  static const
//  Component aTemplateRoot = wrapSimpleName(OUString::createFromAscii("org.openoffice.Templates"));

    Component aTemplateModule = wrapSimpleName(_rModule);
    Component aTemplateName   = wrapSimpleName(_rLogicalTemplateName);

    Path::Rep aResult(aTemplateName);
    aResult.prepend(aTemplateModule);
//    aResult.prepend(aTemplateRoot);

    return AbsolutePath(aResult);
}

// -------------------------------------------------------------------------
data::TreeAccessor TreeManager::requestTemplate(data::Accessor const& /*_aSourceAccessor*/,
                                                Name const& _rName, Name const& _rModule
                                                ) CFG_UNO_THROW_ALL(  )
{
    OSL_ENSURE(!_rName.isEmpty(), "TreeManager::requestTemplate : invalid template name !");

    CFG_TRACE_INFO("TreeManager: going to get a template named %s", OUSTRING2ASCII(_rName.toString()));

    AbsolutePath aTemplateLocation = encodeTemplateLocation(_rName, _rModule);
    Name aCacheModule = aTemplateLocation.getModuleName();

    osl::MutexGuard aGuard(m_aTemplates.mutex());

    data::Accessor aTemplatesAccessor( getTemplates().getDataSegment(aCacheModule) );

    if (!getTemplates().hasNode(aTemplatesAccessor,aTemplateLocation))
    {
        aTemplatesAccessor.clear();

        CFG_TRACE_INFO_NI("TreeManager: cache miss. going to load the template");
        backend::TemplateRequest aQuery( _rName, _rModule );

        backend::CacheLocation aLoadedLocation = getCacheLoader()->loadTemplate(aQuery);
        if (aLoadedLocation.isNull())
        {
            CFG_TRACE_ERROR_NI("TreeManager: requested template module not found");
            throw com::sun::star::container::
                    NoSuchElementException( MAKEUSTRING("Requested template module not found"), NULL);
        }

        CFG_TRACE_INFO_NI("TreeManager: attaching to loaded template module");

        aTemplatesAccessor = data::Accessor(getTemplates().attachDataSegment(aLoadedLocation.segment,aCacheModule));
        OSL_ENSURE(aTemplatesAccessor.is(),"Cannot attach to loaded component");

        // create a client ref count on the template module
        getTemplates().acquireNode(aTemplatesAccessor,aTemplateLocation);
    }
    else
    {
        CFG_TRACE_INFO_NI("TreeManager: template module found in cache");
        OSL_ENSURE(aTemplatesAccessor.is(),"No accessor for existing data ?");
    }

    data::TreeAddress aTemplateAddr = getTemplates().getTemplateTree(aTemplatesAccessor,aTemplateLocation);
    if (aTemplateAddr.isNull())
    {
        CFG_TRACE_ERROR_NI("TreeManager: template not found in module");
        throw com::sun::star::container::
                    NoSuchElementException( MAKEUSTRING("Unknown template. Type description could not be found in the given module."), NULL);
    }
    return data::TreeAccessor(aTemplatesAccessor,aTemplateAddr);
}

// -------------------------------------------------------------------------
void TreeManager::saveAndNotifyUpdate(data::Accessor const& _aChangedDataAccessor, TreeChangeList const& aChangeTree) CFG_UNO_THROW_ALL(  )
{
    {
        CFG_TRACE_INFO("TreeManager: committing an Update to the cache controller");
        RequestOptions aOptions = aChangeTree.getOptions();;
        //Modify RequestOptions - suppress async commit, if disabled
        if(!m_bEnableAsync)
            aOptions.enableAsync(false);

        backend::UpdateRequest anUpdate(
                                & aChangeTree.root,
                                aChangeTree.getRootNodePath(),
                                aOptions);

        getCacheLoader()->saveAndNotify(anUpdate);
        CFG_TRACE_INFO_NI("TreeManager: committing done");
    }

    // notification should be done via the cache loader
    // this->ConfigChangeBroadcaster::fireChanges(_aChangedDataAccessor, aChangeTree, false);
}

// -------------------------------------------------------------------------
void TreeManager::fireChanges(data::Accessor const& _aChangedDataAccessor, TreeChangeList const& aChangeTree, sal_Bool _bError)
{
    CFG_TRACE_INFO("TreeManager: broadcasting changes");
    ConfigChangeBroadcaster::fireChanges(_aChangedDataAccessor, aChangeTree, _bError);
}

// -----------------------------------------------------------------------------
void TreeManager::updateTree(memory::UpdateAccessor& _aAccessToken, TreeChangeList& _aChanges) CFG_UNO_THROW_ALL(  )
{
    CFG_TRACE_INFO("TreeManager: updating the cache from a changes list");

    backend::UpdateInstance anUpdate(&_aChanges.root,_aChanges.getRootNodePath());

    CacheRef aCache = m_aCacheList.get(_aChanges.getOptions());

    if (!aCache.is())
    {
        CFG_TRACE_ERROR_NI("TreeManager: Cache access to update into does not exist !");
        OSL_ENSURE(aCache.is(),"TreeManager: Cache access to update into does not exist ! Where does the update access come from ?");
        throw lang::DisposedException(OUString::createFromAscii("Tree to be updated was already disposed"), NULL);
    }

    // merge the changes into the tree
    aCache->applyUpdate(_aAccessToken, anUpdate);

    CFG_TRACE_INFO_NI("TreeManager: cache update done");
}

// -----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void TreeManager::releaseSubtree( AbsolutePath const& aSubtreePath, const RequestOptions& _aOptions ) CFG_NOTHROW()
{
    CFG_TRACE_INFO("TreeManager: releasing subtree '%s' for entity '%s' with locale '%s'", OUSTRING2ASCII(aSubtreePath.toString()), OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );

    CacheRef aCache = m_aCacheList.get(_aOptions);

    OSL_ENSURE(aCache.is(),"TreeManager: No local data to release");

    if (aCache.is())
    {
        CFG_TRACE_INFO_NI("TreeManager: decrementing refcount for subtree '%s'", OUSTRING2ASCII(aSubtreePath.toString()) );
        if (aCache->releaseNode(aSubtreePath) == 0)
        {
            backend::ComponentRequest aComponentDesc(aSubtreePath.getModuleName(),_aOptions);
            BackendCacheRef xBackendCache = maybeGetBackendCache();
            if (xBackendCache.is()) xBackendCache->freeComponent(aComponentDesc);
        }
    }
}
// ----------------------------------------------------------------------------
void TreeManager::refreshAll() CFG_UNO_THROW_ALL(  )
{
    //Find what components are in cache and that have client references and reload
    //such components.
     BackendCacheRef aCacheRef = maybeGetBackendCache();
     if (aCacheRef.is()) aCacheRef->refreshAllComponents();
}
// ----------------------------------------------------------------------------
void TreeManager::flushAll()CFG_NOTHROW()
{
     BackendCacheRef aCacheRef = maybeGetBackendCache();
     if (aCacheRef.is()) aCacheRef->flushPendingUpdates();
}
//-----------------------------------------------------------------------------
void TreeManager::enableAsync(const sal_Bool& bEnableAsync) CFG_NOTHROW()
{
    m_bEnableAsync = bEnableAsync;
}

//-----------------------------------------------------------------------------
void TreeManager::disposeData(const RequestOptions& _aOptions) CFG_NOTHROW()
{
    CFG_TRACE_INFO("TreeManager: disposing data by options");

    if (_aOptions.getLocale().getLength() != 0)
    {
        OSL_ENSURE(_aOptions.getEntity().getLength() != 0, "TreeManager: Cannot dispose locale without user");
        CFG_TRACE_INFO_NI( "TreeManager: Disposing data for options: ENTITY='%s' and LOCALE = '%s'",
                                OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );

        this->disposeOne( _aOptions );
    }
    else if (_aOptions.getEntity().getLength() != 0)
    {
        CFG_TRACE_INFO_NI( "TreeManager: Disposing data for user: '%s'", OUSTRING2ASCII(_aOptions.getEntity()) );

        this->disposeUser(_aOptions );
    }
    else
    {
        OSL_ENSURE(false, "TreeManager: Cannot dispose: neither user nor locale specified in options");
    }
    CFG_TRACE_INFO_NI("TreeManager: disposing data done");
}

// INotifyListener
// ----------------------------------------------------------------------------
void TreeManager::nodeUpdated(TreeChangeList& _rChanges)
{
    CFG_TRACE_INFO("TreeManager: nodeUpdated");
    try
    {
        CacheRef aCache = m_aCacheList.get(_rChanges.getOptions());

        if (aCache.is())
        {
            // first approve the changes and merge them with the current tree
            AbsolutePath aSubtreeName = _rChanges.getRootNodePath();

            memory::Accessor aAccessor( aCache->getDataSegment(aSubtreeName) );
            OSL_ENSURE(aAccessor.is(), "TreeManager::nodeUpdated : cannot access cache !");

            data::NodeAddress aCacheTree = aCache->findInnerNode(aAccessor,aSubtreeName);
            OSL_ENSURE(aCacheTree.is(), "TreeManager::nodeUpdated : node not found in cache!");

            if (aCacheTree.is())
                this->fireChanges(aAccessor,_rChanges,false);
        }
    }
    catch (uno::RuntimeException&)
    {
        CFG_TRACE_ERROR_NI("TreeManager::nodeUpdated : could not notify !");
    }
    CFG_TRACE_INFO_NI("TreeManager: nodeUpdated done");
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ICachedDataListener
// ----------------------------------------------------------------------------

void TreeManager::disposing(backend::ICachedDataProvider & _rProvider)   CFG_NOTHROW()
{
    CFG_TRACE_INFO("TreeManager: provider is being disposed");
    this->dispose();
}
// ----------------------------------------------------------------------------

void TreeManager::componentCreated(backend::ComponentRequest const & ) CFG_NOTHROW()
{
    CFG_TRACE_INFO("TreeManager: component was created");
}
// ----------------------------------------------------------------------------

void TreeManager::componentChanged(backend::UpdateRequest  const & _anUpdate)     CFG_NOTHROW()
{
    TreeChangeList aChanges(_anUpdate.getOptions(),
                            _anUpdate.getUpdateRoot().location(),
                            *_anUpdate.getUpdateData(),
                            SubtreeChange::DeepChildCopy() );

    this->nodeUpdated(aChanges);
}
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
} // namespace
