////////////////////////////////////////////////////////////////////////
//
// $Id: Registry.h,v 1.16 2001/08/10 01:11:35 rhatcher Exp $
//
// Registry
//
// Package: Registry
//
// A Registry is a stash of values of arbitrary types which are
// accessed by names of type string.
//
// Contact: bv@bnl.gov
//
// Created on: Wed Oct 25 17:13:16 2000
//
////////////////////////////////////////////////////////////////////////

#ifndef REGISTRY_H
#define REGISTRY_H

#include <iostream>
#include <map>
#include <list>
#include <string>

#include "Rtypes.h"
#include "TNamed.h"

// This will get removed when more people's C++ compiler supports
// Templated Member Functions (ie, moving from gcc 2.91 (egcs) to 
// gcc 2.95
#define NO_TEMPATED_FUNCITONS
#define REGISTRY_NEED_CHAR_INTERFACE

///
class RegistryItem;

///
class Registry : public TNamed
{

public:
    ///
    typedef map<string,RegistryItem*> tRegMap;
    ///
    typedef void (*ErrorHandler)(void);

    ///
    Registry(bool readonly = true);
    ///
    Registry(const Registry& rhs); /// deep copy constructor
    virtual ~Registry();
    ///
    Registry& operator=(const Registry& rhs); // deep copy assignment

    /// Return number of entries
    unsigned int Size() const { return fMap.size(); }

    /// Check if key exists
    bool KeyExists(string key) const;
#ifdef REGISTRY_NEED_CHAR_INTERFACE
// This function duplicates functionality the above STL string version 
/// but are callable from c strings (and thus from CINT)
    bool KeyExists(const char* key) const;
#endif

    /// Clear Registry - deletes all items
    void Clear(void);           //*MENU*

    // Dump to cerr.
    void Dump(void) const;      //*MENU*

    // Print to cout (without extraneous bits of Dump())
    virtual void Print(const char *option="") const;
    
    /// Control if an existing value can be set
    virtual bool ValuesLocked(void) const { return fValuesLocked; }
    ///
    virtual void LockValues(void) { fValuesLocked = true; } //*MENU*
    virtual void UnLockValues(void) { fValuesLocked = false; } //*MENU*

    // Control if new key/value pairs can be added.
    virtual bool KeysLocked(void) const { return fKeysLocked; }
    ///
    virtual void LockKeys(void) { fKeysLocked = true; } //*MENU*
    virtual void UnLockKeys(void) { fKeysLocked = false; } //*MENU*

    void SetErrorHandler(ErrorHandler eh) { fErrorHandler = eh; }


#ifdef NO_TEMPATED_FUNCITONS

    ///
    bool Get(string key, char& c) const;
///    bool Get(string key, const char*& s) const;
    bool Get(string key, char*& s) const;
    ///
    bool Get(string key, int& i) const;
    ///
    bool Get(string key, double& d) const;

    ///
    char        GetChar(string key) const;
    ///
    const char* GetCharString(string key) const;
    ///
    int         GetInt(string key) const;
    ///
    double      GetDouble(string key) const;

    ///
    bool Set(string key, char c);
    ///
    bool Set(string key, const char* s);
    ///
    bool Set(string key, int i);
    ///
    bool Set(string key, double d);

#ifdef REGISTRY_NEED_CHAR_INTERFACE
// These functions duplicate functionality the above STL string version 
/// but are callable from c strings (and thus from CINT)
    bool Get(const char* key, char& c) const;
///    bool Get(const char* key, const char*& s) const;
    bool Get(const char* key, char*& s) const;
    ///
    bool Get(const char* key, int& i) const;
    ///
    bool Get(const char* key, double& d) const;

    ///
    char        GetChar(const char* key) const;
    ///
    const char* GetCharString(const char* key) const;
    ///
    int         GetInt(const char* key) const;
    ///
    double      GetDouble(const char* key) const;

    ///
    bool Set(const char* key, char c);
    ///
    bool Set(const char* key, const char* s);
    ///
    bool Set(const char* key, int i);
    ///
    bool Set(const char* key, double d);
#endif

#else  //  NO_TEMPATED_FUNCITONS

    /// Get/Set arbitrary types by pointer
    template<class T> const T* GetPtr(string key) const;
    template<class T> bool Get(string key, T& val) const;
    template<class T> bool Set(string key, T& val);

#endif //  NO_TEMPATED_FUNCITONS

    class RegistryKey
    {
        
    public:
        ///
        RegistryKey();
        ///
        RegistryKey(const Registry* r);
        ///
        virtual ~RegistryKey();
        
        ///
        const char* operator()(void);
    
    private:
        
        ///
        const Registry* fReg;
        ///
        map<string,RegistryItem*>::iterator fIt;
    };                              /// end of class RegistryKey

    RegistryKey Key(void) const;

private:
    ///
    bool fValuesLocked;
    ///
    bool fKeysLocked;
    ///
    ErrorHandler fErrorHandler;
#ifndef __CINT__
    ///
    friend class RegistryKey;
    ///
    template<class T> bool SetPtr(string key, T* val);
    tRegMap fMap;
#endif

    ClassDef(Registry,1)
};                              // end of class Registry


#include "Registry/RegistryItemXxx.h"

#ifndef __CINT__

#ifdef NO_TEMPATED_FUNCITONS

// See Registry.cxx

#else  //  NO_TEMPATED_FUNCITONS

template<class T> 
const T* Registry::GetPtr(string key) const
{
    ///
    tRegMap::const_iterator mit = fMap.find(key);
    ///
    if (mit == fMap.end()) {
        cerr << "Registry::Get: No such key: " << key << endl;
        return 0;
    }

    ///
    RegistryItemXxx<T>* rix = 
        dynamic_cast<RegistryItemXxx<T>*>(mit->second);
    ///
    if (rix == 0) {
        cerr << "Registry:Get: type mismatch\n";
        return 0;
    }

    ///
    return rix->Get();
}

///
template<class T> 
bool Registry::Get(string key, T& val) const
{
    ///
    const T* tptr = GetPtr<T>(key);
    ///
    if (tptr) {
        val = *tptr;
        return true;
    }
    ///
    else return false;
}

///
template<class T> 
bool Registry::SetPtr(string key, T* val)
{
    ///
    tRegMap::iterator mit = fMap.find(key);
    ///
    if (mit != fMap.end()) {    // Found it
        if (fValuesLocked) {
            cerr << "Registry::Set: Values are locked - not overwriting `"
                 << key << "'\n";
            return false;
        }
        delete mit->second;
        fMap.erase(mit);
    }
    ///
    else {                      // didn't find it
        if (fKeysLocked) {
            cerr << "Registry::Set: Keys are locked - not adding `" 
                 << key << "'\n";
            return false;
        }
    }

    ///
    RegistryItem* ri = new RegistryItemXxx<T>(val);
    ///
    fMap[key] = ri;
    ///
    return true;
}

///
template<class T> 
bool Registry::Set(string key, T& val)
{
    ///
    return SetPtr(key, new T(val));
}

#endif // NO_TEMPATED_FUNCITONS

#ifdef REGISTRY_NEED_CHAR_INTERFACE
//
// These functions duplicate functionality the above STL string version 
// but are callable from c strings (and thus from CINT)
///
inline bool Registry::KeyExists(const char* key) const
{ return KeyExists(string(key)); }

///
inline bool Registry::Get(const char* key, char& c) const
{ return Get(string(key),c); }
///
inline bool Registry::Get(const char* key, char*& s) const
{ return Get(string(key),s); }
///
inline bool Registry::Get(const char* key, int& i) const
{ return Get(string(key),i); }
///
inline bool Registry::Get(const char* key, double& d) const
{ return Get(string(key),d); }

///
inline char Registry::GetChar(const char* key) const
{ return GetChar(string(key)); }
///
inline const char* Registry::GetCharString(const char* key) const
{ return GetCharString(string(key)); }
///
inline int Registry::GetInt(const char* key) const
{ return GetInt(string(key)); }
///
inline double Registry::GetDouble(const char* key) const
{ return GetDouble(string(key)); }

///
inline bool Registry::Set(const char* key, char c)
{ return Set(string(key),c); }
///
inline bool Registry::Set(const char* key, const char* s)
{ return Set(string(key),s); }
///
inline bool Registry::Set(const char* key, int i)
{ return Set(string(key),i); }
///
inline bool Registry::Set(const char* key, double d)
{ return Set(string(key),d); }

#endif // REGISTRY_NEED_CHAR_INTERFACE

#endif  // __CINT__

#endif  // REGISTRY_H
