/* $Id: User_field.hpp 670272 2023-07-20 17:47:12Z vasilche $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
 *               National Center for Biotechnology Information
 *
 *  This software/database is a "United States Government Work" under the
 *  terms of the United States Copyright Act.  It was written as part of
 *  the author's official duties as a United States Government employee and
 *  thus cannot be copyrighted.  This software/database is freely available
 *  to the public for use. The National Library of Medicine and the U.S.
 *  Government have not placed any restriction on its use or reproduction.
 *
 *  Although all reasonable efforts have been taken to ensure the accuracy
 *  and reliability of the software and data, the NLM and the U.S.
 *  Government do not and cannot warrant the performance or results that
 *  may be obtained by using this software or data. The NLM and the U.S.
 *  Government disclaim all warranties, express or implied, including
 *  warranties of performance, merchantability or fitness for any particular
 *  purpose.
 *
 *  Please cite the author in any work or product based on this material.
 *
 * ===========================================================================
 *
 * Author:  .......
 *
 * File Description:
 *   .......
 *
 * Remark:
 *   This code was originally generated by application DATATOOL
 *   using specifications from the data definition file
 *   'general.asn'.
 */

#ifndef OBJECTS_GENERAL_USER_FIELD_HPP
#define OBJECTS_GENERAL_USER_FIELD_HPP


// generated includes
#include <objects/general/User_field_.hpp>

// generated classes

BEGIN_NCBI_SCOPE

BEGIN_objects_SCOPE // namespace ncbi::objects::

class NCBI_GENERAL_EXPORT CUser_field : public CUser_field_Base
{
    typedef CUser_field_Base Tparent;
public:
    // constructor
    CUser_field(void);
    // destructor
    ~CUser_field(void);

    enum EParseField {
        eParse_String,    ///< Add string even if all numbers
        eParse_Number     ///< Parse a real or integer number, otherwise string
    };

    /// set value
    CUser_field& SetInt(int value);
    CUser_field& SetInt8(Int8 value);
    CUser_field& SetGi(TGi gi);
    CUser_field& SetDouble(double value);
    CUser_field& SetBool(bool value);
    CUser_field& SetString(const char* value);
    CUser_field& SetString(const string& value);

    /// set a data field to a given value
    /// Int8 and TGi values can be stored into 'str' field if
    /// the value doesn't fit into 'int' field
    CUser_field& SetValue(int           value);
    CUser_field& SetValue(Int8          value);
#ifdef NCBI_STRICT_GI
    CUser_field& SetValue(TGi           value);
#endif
    CUser_field& SetValue(double        value);
    CUser_field& SetValue(bool          value);
    CUser_field& SetValue(const char* value);
    CUser_field& SetValue(const string& value);
    CUser_field& SetValue(const char* value, EParseField parse);
    CUser_field& SetValue(const string& value, EParseField parse);
    CUser_field& SetValue(const vector<int>&    value);
    CUser_field& SetValue(const vector<double>& value);
    CUser_field& SetValue(const vector<string>& value);
    CUser_field& SetValue(CUser_object& value);
    CUser_field& SetValue(const vector< CRef<CUser_object> >& value);
    CUser_field& SetValue(const vector< CRef<CUser_field> >& value);

    /// get value
    int GetInt(void) const;
    Int8 GetInt8(void) const;
    TGi GetGi(void) const;
    bool GetBool(void) const;
    double GetDouble(void) const;
    const string& GetString(void) const;

    template<class Type> Type GetValue(void) const;

    /// add fields to the current user field
    CUser_field& AddField(const string& label, int           value);
    CUser_field& AddField(const string& label, Int8          value);
#ifdef NCBI_STRICT_GI
    CUser_field& AddField(const string& label, TGi           value);
#endif
    CUser_field& AddField(const string& label, double        value);
    CUser_field& AddField(const string& label, bool          value);

    CUser_field& AddField(const string& label, const char* value);
    CUser_field& AddField(const string& label, const string& value);
    CUser_field& AddField(const string& label, const char* value,
                          EParseField field);
    CUser_field& AddField(const string& label, const string& value,
                          EParseField field);
    CUser_field& AddField(const string& label, const vector<string>& value);

    CUser_field& AddField(const string& label, const vector<int>&    value);
    CUser_field& AddField(const string& label, const vector<double>& value);

    CUser_field& AddField(const string& label, CUser_object& value);
    CUser_field& AddField(const string& label,
                          const vector< CRef<CUser_object> >& value);
    CUser_field& AddField(const string& label,
                          const vector< CRef<CUser_field> >& value);

    /// Set num field from a container size
    /// Check for overflow and throw CSerialException::eOverflow
    /// if the size doesn't fit into the field
    void SetNumFromSize(size_t value);

    /// Access a named field in this user field.  This will tokenize the
    /// string 'str' on the delimiters; if the field doesn't exist, an
    /// exception will be thrown.
    const CUser_field&     GetField(const string& str,
                                    const string& delim = ".",
                                    NStr::ECase use_case = NStr::eCase) const;

    /// Return a field reference representing the tokenized key, or a
    /// NULL reference if the key doesn't exist.
    CConstRef<CUser_field> GetFieldRef(const string& str,
                                       const string& delim = ".",
                                       NStr::ECase use_case = NStr::eCase) const;

    /// For functions that don't use delims, we instead use a chain of names.
    struct NCBI_GENERAL_EXPORT SFieldNameChain {
        /// Convenience func.  This can be deprecated if a
        /// NStr::Join function is created that takes 
        /// the type of TFieldNameChainUnderlying
        void Join(ostream & out_name_strm, const string & delim = ".") const;

        void operator += (const CTempStringEx & str) {
            m_FieldNameChain.push_back(str);
        }

        bool operator < (const SFieldNameChain & rhs) const {
            return m_FieldNameChain < rhs.m_FieldNameChain;
        }

        typedef vector<CTempStringEx> TFieldNameChainUnderlying;
        TFieldNameChainUnderlying m_FieldNameChain;
    };

    /// Maps field names like the input for GetFieldRef to the user-field.
    typedef map<SFieldNameChain, CConstRef<CUser_field> > TMapFieldNameToRef;

    /// Flags that affect behavior of TMapFieldNameToRef functions.
    enum EFieldMapFlags {
        fFieldMapFlags_ExcludeThis = (1<<0) ///< = 0x1 (excludes this CUser_field's name and mapping to self from results)
    };
    typedef int TFieldMapFlags; ///< holds bitwise OR of "EFieldMapFlags"

    /// Recursively get the map of field names like the input 
    /// for GetFieldRef to the user-field.
    ///
    /// @param out_mapFieldNameToRef
    ///   The results are put into here, but it becomes INVALID if this
    ///   CUser_field or any of its descendents change their label.
    ///   It will NOT be cleared
    ///   before more data is added, and in that case would overwrite any
    ///   item which has the same key.
    /// @param fFieldMapFlags
    ///   Flags that affect behavior of function.
    /// @param parent_name
    ///   Outside users probably don't need this.  It's really for 
    ///   internal recursive calls when building the map.
    void GetFieldsMap(
        CUser_field::TMapFieldNameToRef & out_mapFieldNameToRef,
        TFieldMapFlags fFieldMapFlags = 0,
        const SFieldNameChain & parent_name = SFieldNameChain() ) const;

    /// Access a named field in this user field.  This will tokenize the
    /// string 'str' on the delimiters and recursively add fields where needed
    CUser_field&      SetField(const string& str,
                               const string& delim = ".",
                               NStr::ECase use_case = NStr::eCase);

    /// Return a field reference representing the tokenized key, or a
    /// NULL reference if the key cannot be created for some reason.
    CRef<CUser_field> SetFieldRef(const string& str,
                                  const string& delim = ".",
                                  NStr::ECase use_case = NStr::eCase);

    /// Verify that a named field exists
    bool HasField(const string& str,
                  const string& delim = ".",
                  NStr::ECase use_case = NStr::eCase) const;
                  
    /// Delete the named field.
    /// return true if successful. false if field doesn't exist.
    bool DeleteField(const string& str,
                     const string& delim = ".",
                     NStr::ECase use_case = NStr::eCase);


private:
    // Prohibit copy constructor and assignment operator
    CUser_field(const CUser_field& value);
    CUser_field& operator=(const CUser_field& value);
};



/////////////////// CUser_field inline methods

// constructor
inline
CUser_field::CUser_field(void)
{
}


inline
CUser_field& CUser_field::SetString(const string& value)
{
    SetData().SetStr(value);
    return *this;
}


inline
CUser_field& CUser_field::SetInt(int value)
{
    SetData().SetInt(value);
    return *this;
}


inline
CUser_field& CUser_field::SetBool(bool value)
{
    SetData().SetBool(value);
    return *this;
}


inline
CUser_field& CUser_field::SetDouble(double value)
{
    SetData().SetReal(value);
    return *this;
}


inline
CUser_field& CUser_field::SetValue(const char* value)
{
    return SetString(value);
}


inline
CUser_field& CUser_field::SetValue(const string& value)
{
    return SetString(value);
}


inline
CUser_field& CUser_field::SetValue(int value)
{
    return SetInt(value);
}


inline
CUser_field& CUser_field::SetValue(bool value)
{
    return SetBool(value);
}


inline
CUser_field& CUser_field::SetValue(double value)
{
    return SetDouble(value);
}


inline
CUser_field& CUser_field::SetValue(Int8 value)
{
    return SetInt8(value);
}


inline
CUser_field& CUser_field::SetGi(TGi value)
{
    return SetValue(GI_TO(TIntId, value));
}


#ifdef NCBI_STRICT_GI
inline
CUser_field& CUser_field::SetValue(TGi value)
{
    return SetGi(value);
}
#endif


inline
int CUser_field::GetInt(void) const
{
    return GetData().GetInt();
}


inline
double CUser_field::GetDouble(void) const
{
    return GetData().GetReal();
}


inline
bool CUser_field::GetBool(void) const
{
    return GetData().GetBool();
}


inline
const string& CUser_field::GetString(void) const
{
    return GetData().GetStr();
}


template<>
inline
int CUser_field::GetValue<int>(void) const
{
    return GetInt();
}


template<>
inline
Int8 CUser_field::GetValue<Int8>(void) const
{
    return GetInt8();
}


template<>
inline
double CUser_field::GetValue<double>(void) const
{
    return GetDouble();
}


template<>
inline
bool CUser_field::GetValue<bool>(void) const
{
    return GetBool();
}


template<>
inline
string CUser_field::GetValue<string>(void) const
{
    return GetString();
}


inline
TGi CUser_field::GetGi(void) const
{
    return GI_FROM(TIntId, GetValue<TIntId>());
}


#ifdef NCBI_STRICT_GI
template<>
inline
TGi CUser_field::GetValue<TGi>(void) const
{
    return GetGi();
}
#endif


/////////////////// end of CUser_field inline methods


END_objects_SCOPE // namespace ncbi::objects::

END_NCBI_SCOPE

#endif // OBJECTS_GENERAL_USER_FIELD_HPP
