//
//  File:   hzTmplMapL.h
//
//  Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
//  Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
//  The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
//  Software Foundation, either version 3 of the License, or any later version.
//
//  The HadronZoo C++ Class 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 the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#ifndef hzTmplMapL_h
#define hzTmplMapL_h
#include "hzString.h"
#include "hzLock.h"
#include "hzProcess.h"
#include "hzIsamT.h"
/*
**  The hzLookup template
*/
template<class OBJ> int32_t _fast_str_compare   (const void* pKey, const _hz_vn_Dat* pDN, uint32_t nSlot)
{
    //  Called internally by _hz_tmpl_ISAM::_findDnodeByKey in the case of a set (keys only).
    _hz_map_bkt<hzString,OBJ>*   pBuck ;
    hzString*   key ;
    key = (hzString*) pKey ;
    pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
    return *key > pBuck->m_Keys[nSlot] ? 1 : *key < pBuck->m_Keys[nSlot] ? -1 : 0 ;
}
template<class OBJ> class   hzLookup
{
    //  Category:   Object Collection
    //
    //  The hzLookup template is a special case of a hzMapS providing a memory resident one to one map of strings (hzString) to objects. The strings are
    //  required to be unique and there may only be one object per key. Only the objects can be of any C++, HadronZoo or application specific type.
    //
    //  hzLookup is considered UNORDERED because it uses the fast string compare function (fscompare). This function compares strings as though they
    //  were arrays of int64_t and thus only gives a valid lexical comparison in big-endian CPU architectures.
    _hz_tmpl_ISAM   base ;          //  _hz_set_isam_Value ordered list by value
    hzString        m_NullKey ;     //  Null key
    _mut hzString   m_DefaultKey ;  //  Default key (effectively NULL)
    OBJ             m_NullObj ;     //  Null key
    mutable OBJ     m_DefaultObj ;  //  Default key (effectively NULL)
    //  Prevent copies
    hzLookup<OBJ>   (const hzLookup<OBJ>&) ;
    hzLookup<OBJ>&  operator=   (const hzLookup<OBJ>&) ;
public:
    hzLookup    (void)
    {
        base.Start(sizeof(hzString),sizeof(OBJ)) ;
        base.SetLock(HZ_NOLOCK) ;
        base.m_compare = _fast_str_compare<OBJ> ;
        _hzGlobal_Memstats.m_numMmaps++ ;
    } 
    hzLookup    (hzLockOpt eLock)
    {
        base.Start(sizeof(hzString),sizeof(OBJ)) ;
        base.SetLock(eLock) ;
        base.m_compare = _fast_str_compare<OBJ> ;
        _hzGlobal_Memstats.m_numMmaps++ ;
    } 
    hzLookup    (const hzString& name)
    {
        base.Start(sizeof(hzString),sizeof(OBJ)) ;
        base.SetLock(HZ_NOLOCK) ;
        base.SetName(name) ;
        base.m_compare = _fast_str_compare<OBJ> ;
        _hzGlobal_Memstats.m_numMmaps++ ;
    }
    hzLookup    (hzLockOpt eLock, const hzString& name)
    {
        base.Start(sizeof(hzString),sizeof(OBJ)) ;
        base.SetLock(eLock) ;
        base.SetName(name) ;
        base.m_compare = _fast_str_compare<OBJ> ;
        _hzGlobal_Memstats.m_numMmaps++ ;
    }
    ~hzLookup   (void)  { _hzGlobal_Memstats.m_numSpmaps-- ; }
    //  Init functions
    //void  SetName         (const hzString& name)  { base.SetName(name) ; }
    void    SetLock         (hzLockOpt eLock)       { base.SetLock(eLock) ; }
    //void  SetDefaultObj   (OBJ obj)   { base.SetDefaultObj(obj) ; }
    void    Clear   (void)  { base.Clear() ; }
    //  Insert and delete by key
    hzEcode Insert  (const hzString& key, const OBJ& obj)
    {
        _hzfunc("hzMapS::Insert") ;
        _hz_map_bkt<hzString,OBJ>*  pBuck ;
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base.InsertKeyU(nSlot, &key) ;
        if (pDN)
        {
            pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
            pBuck->m_Keys[nSlot] = key ;
            pBuck->m_Objs[nSlot] = obj ;
            return E_OK ;
        }
        return hzerr(E_CORRUPT, "Failed to Insert") ;
    }
    hzEcode Delete  (const hzString& key)
    {
        _hzfunc("hzMapS:Delete") ;
        _hz_map_bkt<hzString,OBJ>*  pBuck ;
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
        if (!pDN)
            return E_NOTFOUND ;
        pDN = base.DeleteKey(nSlot, &key) ;
        //pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
        //pBuck->m_Keys[nSlot] = m_NullKey ;
        //pBuck->m_Objs[nSlot] = m_NullObj ;
        return E_OK ;
    }
    //  Locate keys or objects by position
    OBJ&    GetObj  (int32_t nIndex) const
    {
        _hz_map_bkt<hzString,OBJ>*  pBuck ;
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base._findDnodeByPos(nSlot, nIndex, false) ;
        if (!pDN)
        {
            m_DefaultObj = m_NullObj ;
            return m_DefaultObj ;
        }
        pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
        return pBuck->m_Objs[nSlot] ;
    }
    const hzString& GetKey  (int32_t nIndex) const
    {
        _hz_map_bkt<hzString,OBJ>*  pBuck ;
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base._findDnodeByPos(nSlot, nIndex, false) ;
        if (!pDN)
        {
            m_DefaultKey = m_NullKey ;
            return m_DefaultKey ;
        }
        pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
        return pBuck->m_Keys[nSlot] ;
    }
    //  Locate elements by value
    bool    Exists      (const hzString& key) const
    {
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
        if (!pDN)
            return false ;
        return true ;
    }
    OBJ&    operator[]  (const hzString& key) const
    {
        _hz_map_bkt<hzString,OBJ>*  pBuck ;
        _hz_vn_Dat* pDN ;
        int32_t     nSlot ;
        pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
        if (!pDN)
        {
            m_DefaultObj = m_NullObj ;
            return m_DefaultObj ;
        }
        pBuck = (_hz_map_bkt<hzString,OBJ>*) pDN->m_pElements ;
        return pBuck->m_Objs[nSlot] ;
    }
    //  Diagnostics
    uint32_t    Nodes       (void) const    { return base.Nodes() ; }
    uint32_t    Count       (void) const    { return base.Count() ; }
    hzEcode     NodeErrors  (void) const    { return base.NodeReport(true) ; }
    hzEcode     NodeReport  (void) const    { return base.NodeReport(false) ; }
} ;
#endif  //  hzTmplMapL_h