#ifndef ConfigurationAccess_hpp
#define ConfigurationAccess_hpp

#include "TreeInterfaces.hpp"
#include "TreeMerger.hpp"
#include "TreeDiff.hpp"
#include "TreeElements.hpp"
#include "PolicyAccess.hpp"
#include "INodeListener.hpp"

namespace apoc { namespace legacy {

/**
  * Class providing access to the policy configuration data, viewed as a single
  * data source. The configuration data is provided in a merged state and can
  * be accessed at the node or property level.
  */
class ConfigurationAccess : public IPolicyListener
{
    public :
        /**
          * Accessor to the configuration access default singleton.
          *
          * @return singleton for access to configuration data for the 
                    default entity.
          */
        static ConfigurationAccess& defaultInstance(void) ;

        /**
          * Constructor for a given entity.
          *
          * @param aEntity  entity name
          */
        explicit ConfigurationAccess(const std::string& aEntity) ;
        virtual ~ConfigurationAccess(void) ;
        /**
          * Returns the node corresponding to a path (formatted as a component
          * and a subpath within that component).
          *
          * @param aPath    node path
          * @return corresponding node or NULL if not found
          */
        Node *getNode(const std::string& aPath) const ;
        /**
          * Get the string value of a configuration key identified by its path.
          *
          * @param aPath    configuration key path
          * @return string value (empty if not found)
          */
        const std::string& getStringValue(const std::string& aPath) const ;
        /**
          * Returns the string list associated to a configuration key identified
          * by its path.
          *
          * @param aPath    configuration key path
          * @return string list value (empty if not found)
          */
        const std::vector<std::string>& getListValue(
                                            const std::string& aPath) const ;
        /**
          * IPolicyListener interface implementation.
          */
        virtual void onComponentAdd(const std::string& aComponent) const ;
        virtual void onComponentModify(const std::string& aComponent) const ;
        virtual void onComponentRemove(const std::string& aComponent) const ;

        /**
          * Node change listener registration methods
          */
        void addListener(const NodePath& aPath, INodeListener *aListener) ;
        void removeListener(const NodePath& aPath, INodeListener *aListener) ;

        /**
          * Component change listener registration methods
          */
        void addComponentListener(const std::string& aComponent, 
                                  IComponentListener *aListener) ;
        void removeComponentListener(const std::string& aComponent,
                                     IComponentListener *aListener) ;

    protected :
    private :
        // Caching of the trees per component name.
        typedef std::map<std::string, Tree *> TreeMap ;
        mutable TreeMap mTrees ;
        // Listeners for a given component.
        typedef std::map<std::string, DiffListener *> DiffListenerMap;
        DiffListenerMap mDiffListeners ;
        // Registered PAPI listeners per component.
        std::map<std::string, int>  mPolicyAccessListeners;
        // Access to the policy data.
        PolicyAccess mPolicyAccess ;

        // Default constructor private to enforce singleton.
        ConfigurationAccess(void) ;
        /**
          * Returns the tree corresponding to a component, loading it if 
          * necessary.
          *
          * @param aName    component name
          * @return tree object or NULL if non-existent
          */
        Tree *getTree(const std::string& aName) const ;
        /**
          * Returns the listeners container for a component.
          */
        DiffListener *getListeners(const std::string& aComponent) const ;
        /**
          * Creates if necessary the listeners container for a component.
          */
        DiffListener *createListeners(const std::string& aComponent) ;

        void onComponentChange(const std::string& aComponent) const ;

        // Block the copy and assignment operations on ConfigurationAccess 
        ConfigurationAccess(const ConfigurationAccess&) ;
        ConfigurationAccess& operator = (const ConfigurationAccess&) ;
} ;

} } // apoc.legacy

#endif // ConfigurationAccess_hpp

