#pragma once

// ------------------------------------------------------------------------------------------------
#include "Core/Common.hpp"

// ------------------------------------------------------------------------------------------------
#include <SimpleIni.h>

// ------------------------------------------------------------------------------------------------
namespace SqMod {

/* ------------------------------------------------------------------------------------------------
 * Allows the user to inspect the result of certain operations and act accordingly.
*/
class IniResult
{
private:

    // --------------------------------------------------------------------------------------------
    String      m_Action; // The action that was performed.
    SQInteger   m_Result; // The internal result code.

public:

    /* --------------------------------------------------------------------------------------------
     * Construct with no specific action or result.
    */
    IniResult()
        : m_Action("unknown action"), m_Result(SI_OK)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Construct with no specific result.
    */
    explicit IniResult(const SQChar * action)
        : m_Action(!action ? _SC("") : action), m_Result(SI_OK)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Construct with no specific action.
    */
    explicit IniResult(SQInteger result)
        : m_Action("unknown action"), m_Result(result)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Construct with specific action and result.
    */
    IniResult(const SQChar * action, SQInteger result)
        : m_Action(!action ? _SC("") : action), m_Result(result)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    IniResult(const IniResult & o) = default;

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~IniResult() = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    IniResult & operator = (const IniResult & o) = default;

    /* --------------------------------------------------------------------------------------------
     * Perform an equality comparison between two results.
    */
    bool operator == (const IniResult & o) const
    {
        return (m_Result == o.m_Result);
    }

    /* --------------------------------------------------------------------------------------------
     * Perform an inequality comparison between two results.
    */
    bool operator != (const IniResult & o) const
    {
        return (m_Result != o.m_Result);
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to boolean for use in boolean operations.
    */
    operator bool () const // NOLINT(google-explicit-constructor)
    {
        return (m_Result >= 0);
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to compare two instances of this type.
    */
    SQMOD_NODISCARD int32_t Cmp(const IniResult & o) const
    {
        if (m_Result == o.m_Result)
        {
            return 0;
        }
        else if (m_Result > o.m_Result)
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return m_Action.c_str();
    }

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid INI result.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return (m_Result >= 0);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the associated action.
    */
    SQMOD_NODISCARD const SQChar * GetAction() const
    {
        return m_Action.c_str();
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the resulted code.
    */
    SQMOD_NODISCARD SQInteger GetResult() const
    {
        return m_Result;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the resulted code.
    */
    void Check() const;
};

/* ------------------------------------------------------------------------------------------------
 * Manages a reference counted INI document instance.
*/
class IniDocumentRef
{
    // --------------------------------------------------------------------------------------------
    friend class IniDocument;

public:

    // --------------------------------------------------------------------------------------------
    typedef CSimpleIniA     Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*           Pointer; // Pointer to the managed type.
    typedef const Type*     ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&           Reference; // Reference to the managed type.
    typedef const Type&     ConstRef; // Constant reference to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef unsigned int    Counter; // Reference counter type.

    /* --------------------------------------------------------------------------------------------
     * Validate the document reference and throw an error if invalid.
    */
    void Validate() const;

private:

    // --------------------------------------------------------------------------------------------
    Pointer     m_Ptr; // The document reader, writer and manager instance.
    Counter*    m_Ref; // Reference count to the managed instance.

    /* --------------------------------------------------------------------------------------------
     * Grab a strong reference to a document instance.
    */
    void Grab()
    {
        if (m_Ptr)
        {
            ++(*m_Ref);
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Drop a strong reference to a document instance.
    */
    void Drop()
    {
        if (m_Ptr && --(*m_Ref) == 0)
        {
            delete m_Ptr;
            delete m_Ref;
            m_Ptr = nullptr;
            m_Ref = nullptr;
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Base constructor.
    */
    IniDocumentRef(bool utf8, bool multikey, bool multiline)
        : m_Ptr(new Type(utf8, multikey, multiline)), m_Ref(new Counter(1))
    {
        /* ... */
    }

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor (null).
    */
    IniDocumentRef()
        : m_Ptr(nullptr), m_Ref(nullptr)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    IniDocumentRef(const IniDocumentRef & o)
        : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)

    {
        Grab();
    }

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    IniDocumentRef(IniDocumentRef && o) noexcept
        : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)

    {
        o.m_Ptr = nullptr;
        o.m_Ref = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~IniDocumentRef()
    {
        Drop();
    }

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    IniDocumentRef & operator = (const IniDocumentRef & o) noexcept // NOLINT(bugprone-unhandled-self-assignment)
    {
        if (m_Ptr != o.m_Ptr)
        {
            Drop();
            m_Ptr = o.m_Ptr;
            m_Ref = o.m_Ref;
            Grab();
        }
        return *this;
    }

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    IniDocumentRef & operator = (IniDocumentRef && o) noexcept
    {
        if (m_Ptr != o.m_Ptr)
        {
            m_Ptr = o.m_Ptr;
            m_Ref = o.m_Ref;
            o.m_Ptr = nullptr;
            o.m_Ref = nullptr;
        }
        return *this;
    }

    /* --------------------------------------------------------------------------------------------
     * Perform an equality comparison between two document instances.
    */
    bool operator == (const IniDocumentRef & o) const
    {
        return (m_Ptr == o.m_Ptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Perform an inequality comparison between two document instances.
    */
    bool operator != (const IniDocumentRef & o) const
    {
        return (m_Ptr != o.m_Ptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to boolean for use in boolean operations.
    */
    operator bool () const // NOLINT(google-explicit-constructor)
    {
        return static_cast< bool >(m_Ptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to the managed instance pointer.
    */
    operator Pointer () // NOLINT(google-explicit-constructor)
    {
        return m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to the managed instance pointer.
    */
    operator ConstPtr () const // NOLINT(google-explicit-constructor)
    {
        return m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to the managed instance reference.
    */
    operator Reference () // NOLINT(google-explicit-constructor)
    {
        assert(m_Ptr);
        return *m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Implicit conversion to the managed instance reference.
    */
    operator ConstRef () const // NOLINT(google-explicit-constructor)
    {
        assert(m_Ptr);
        return *m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Member operator for dereferencing the managed pointer.
    */
    Pointer operator -> () const
    {
        assert(m_Ptr);
        return m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Indirection operator for obtaining a reference of the managed pointer.
    */
    Reference operator * () const
    {
        assert(m_Ptr);
        return *m_Ptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the number of active references to the managed instance.
    */
    SQMOD_NODISCARD Counter Count() const
    {
        return (m_Ptr && m_Ref) ? (*m_Ref) : 0;
    }
};

/* ------------------------------------------------------------------------------------------------
 * Class that can access and iterate a series of entries in the INI document.
*/
class IniEntries
{
    // --------------------------------------------------------------------------------------------
    friend class IniDocument;

protected:

    // --------------------------------------------------------------------------------------------
    typedef IniDocumentRef::Type::TNamesDepend     Container;

    // --------------------------------------------------------------------------------------------
    typedef Container::iterator                 Iterator;

    /* --------------------------------------------------------------------------------------------
     * Default constructor.
    */
    IniEntries(const IniDocumentRef & ini, Container & list) // NOLINT(modernize-pass-by-value)
        : m_Doc(ini), m_List(), m_Elem()
    {
        m_List.swap(list);
        Reset();
    }

private:

    // ---------------------------------------------------------------------------------------------
    IniDocumentRef     m_Doc; // The document that contains the elements.
    Container       m_List; // The list of elements to iterate.
    Iterator        m_Elem; // The currently processed element.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    IniEntries()
        : m_Doc(), m_List(), m_Elem(m_List.end())
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    IniEntries(const IniEntries & o)
        : m_Doc(o.m_Doc), m_List(o.m_List), m_Elem()
    {
        Reset();
    }

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~IniEntries() = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    IniEntries & operator = (const IniEntries & o)
    {
        m_Doc = o.m_Doc;
        m_List = o.m_List;
        Reset();
        return *this;
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to compare two instances of this type.
    */
    SQMOD_NODISCARD int32_t Cmp(const IniEntries & o) const;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return GetItem();
    }

    /* --------------------------------------------------------------------------------------------
     * Return whether the current element is valid and can be accessed.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return !(m_List.empty() || m_Elem == m_List.end());
    }

    /* --------------------------------------------------------------------------------------------
     * Return whether the entry list is empty.
    */
    SQMOD_NODISCARD bool IsEmpty() const
    {
        return m_List.empty();
    }

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to this document instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Doc.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Return the total entries in the list.
    */
    SQMOD_NODISCARD int32_t GetSize() const
    {
        return static_cast< int32_t >(m_List.size());
    }

    /* --------------------------------------------------------------------------------------------
     * Reset the internal iterator to the first element.
    */
    void Reset()
    {
        if (m_List.empty())
        {
            m_Elem = m_List.end();
        }
        else
        {
            m_Elem = m_List.begin();
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Go to the next element.
    */
    void Next();

    /* --------------------------------------------------------------------------------------------
     * Go to the previous element.
    */
    void Prev();

    /* --------------------------------------------------------------------------------------------
     * Advance a certain number of elements.
    */
    void Advance(int32_t n);

    /* --------------------------------------------------------------------------------------------
     * Retreat a certain number of elements.
    */
    void Retreat(int32_t n);

    /* --------------------------------------------------------------------------------------------
     * Sort the entries using the default options.
    */
    void Sort()
    {
        if (!m_List.empty())
        {
            m_List.sort(IniDocumentRef::Type::Entry::KeyOrder());
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Sort the entries by name of key only.
    */
    void SortByKeyOrder()
    {
        if (!m_List.empty())
        {
            m_List.sort(IniDocumentRef::Type::Entry::KeyOrder());
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Sort the entries by their load order and then name of key.
    */
    void SortByLoadOrder()
    {
        if (!m_List.empty())
        {
            m_List.sort(IniDocumentRef::Type::Entry::LoadOrder());
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the string value of the current element item.
    */
    SQMOD_NODISCARD const SQChar * GetItem() const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve the string value of the current element comment.
    */
    SQMOD_NODISCARD const SQChar * GetComment() const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve the order of the current element.
    */
    SQMOD_NODISCARD int32_t GetOrder() const;
};

/* ------------------------------------------------------------------------------------------------
 * Class that can read/write and alter the contents of INI files.
*/
class IniDocument
{
protected:

    // --------------------------------------------------------------------------------------------
    typedef IniDocumentRef::Type::TNamesDepend Container;

private:

    // ---------------------------------------------------------------------------------------------
    IniDocumentRef     m_Doc; // The main INI document instance.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor.
    */
    IniDocument()
        : m_Doc(false, false, true)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Explicit constructor.
    */
    explicit IniDocument(bool utf8)
        : m_Doc(utf8, false, true)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Explicit constructor.
    */
    IniDocument(bool utf8, bool multikey)
        : m_Doc(utf8, multikey, true)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Explicit constructor.
    */
    IniDocument(bool utf8, bool multikey, bool multiline)
        : m_Doc(utf8, multikey, multiline)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor. (disabled)
    */
    IniDocument(const IniDocument & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~IniDocument() = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator. (disabled)
    */
    IniDocument & operator = (const IniDocument & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to compare two instances of this type.
    */
    SQMOD_NODISCARD int32_t Cmp(const IniDocument & o) const;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const // NOLINT(readability-convert-member-functions-to-static)
    {
        return _SC("");
    }

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid INI document.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Doc;
    }

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to this document instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Doc.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * See whether any data has been loaded into this document.
    */
    SQMOD_NODISCARD bool IsEmpty() const
    {
        return m_Doc->IsEmpty();
    }

    /* --------------------------------------------------------------------------------------------
     * Deallocate all memory stored by this document.
    */
    void Reset() const
    {
        m_Doc->Reset();
    }

    /* --------------------------------------------------------------------------------------------
     * See whether the INI data is treated as unicode.
    */
    SQMOD_NODISCARD bool GetUnicode() const
    {
        return m_Doc->IsUnicode();
    }

    /* --------------------------------------------------------------------------------------------
     * Set whether the INI data should be treated as unicode.
    */
    void SetUnicode(bool toggle)
    {
        m_Doc->SetUnicode(toggle);
    }

    /* --------------------------------------------------------------------------------------------
     * See whether multiple identical keys be permitted in the file.
    */
    SQMOD_NODISCARD bool GetMultiKey() const
    {
        return m_Doc->IsMultiKey();
    }

    /* --------------------------------------------------------------------------------------------
     * Set whether multiple identical keys be permitted in the file.
    */
    void SetMultiKey(bool toggle)
    {
        m_Doc->SetMultiKey(toggle);
    }

    /* --------------------------------------------------------------------------------------------
     * See whether data values are permitted to span multiple lines in the file.
    */
    SQMOD_NODISCARD bool GetMultiLine() const
    {
        return m_Doc->IsMultiLine();
    }

    /* --------------------------------------------------------------------------------------------
     * Set whether data values are permitted to span multiple lines in the file.
    */
    void SetMultiLine(bool toggle)
    {
        m_Doc->SetMultiLine(toggle);
    }

    /* --------------------------------------------------------------------------------------------
     * See whether spaces are added around the equals sign when writing key/value pairs out.
    */
    SQMOD_NODISCARD bool GetSpaces() const
    {
        return m_Doc->UsingSpaces();
    }

    /* --------------------------------------------------------------------------------------------
     * Set whether spaces are added around the equals sign when writing key/value pairs out.
    */
    void SetSpaces(bool toggle)
    {
        m_Doc->SetSpaces(toggle);
    }

    /* --------------------------------------------------------------------------------------------
     * Load an INI file from disk into memory.
    */
    IniResult LoadFile(const SQChar * filepath);

    /* --------------------------------------------------------------------------------------------
     * Load INI file data direct from a string. (LoadString collides with the windows api)
    */
    IniResult LoadData(const SQChar * source)
    {
        return LoadData(source, -1);
    }

    /* --------------------------------------------------------------------------------------------
     * Load INI file data direct from a string. (LoadString collides with the windows api)
    */
    IniResult LoadData(const SQChar * source, int32_t size);

    /* --------------------------------------------------------------------------------------------
     * Save an INI file from memory to disk.
    */
    IniResult SaveFile(const SQChar * filepath)
    {
        return SaveFile(filepath, true);
    }

    /* --------------------------------------------------------------------------------------------
     * Save an INI file from memory to disk.
    */
    IniResult SaveFile(const SQChar * filepath, bool signature);

    /* --------------------------------------------------------------------------------------------
     * Save the INI data to a string.
    */
    Object SaveData(bool signature);

    /* --------------------------------------------------------------------------------------------
     * Retrieve all section names.
    */
    SQMOD_NODISCARD IniEntries GetAllSections() const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve all unique key names in a section.
    */
    SQMOD_NODISCARD IniEntries GetAllKeys(const SQChar * section) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve all values for a specific key.
    */
    SQMOD_NODISCARD IniEntries GetAllValues(const SQChar * section, const SQChar * key) const;

    /* --------------------------------------------------------------------------------------------
     * Query the number of keys in a specific section.
    */
    SQMOD_NODISCARD int32_t GetSectionSize(const SQChar * section) const;

    /* --------------------------------------------------------------------------------------------
     * See whether a certain key has multiple instances.
    */
    SQMOD_NODISCARD bool HasMultipleKeys(const SQChar * section, const SQChar * key) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value for a specific key.
    */
    SQMOD_NODISCARD const char * GetValue(const SQChar * section, const SQChar * key, const SQChar * def) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve a numeric value for a specific key.
    */
    SQMOD_NODISCARD SQInteger GetInteger(const SQChar * section, const SQChar * key, SQInteger def) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve a numeric value for a specific key.
    */
    SQMOD_NODISCARD SQFloat GetFloat(const SQChar * section, const SQChar * key, SQFloat def) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve a boolean value for a specific key.
    */
    SQMOD_NODISCARD bool GetBoolean(const SQChar * section, const SQChar * key, bool def) const;

    /* --------------------------------------------------------------------------------------------
     * Add or update a section or value.
    */
    IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value)
    {
        return SetValue(section, key, value, false, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a section or value.
    */
    IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value, bool force)
    {
        return SetValue(section, key, value, force, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a section or value.
    */
    IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value, bool force, const SQChar * comment);

    /* --------------------------------------------------------------------------------------------
     * Add or update a numeric value.
    */
    IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value)
    {
        return SetInteger(section, key, value, false, false, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a numeric value.
    */
    IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex)
    {
        return SetInteger(section, key, value, hex, false, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a numeric value.
    */
    IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex, bool force)
    {
        return SetInteger(section, key, value, hex, force, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a numeric value.
    */
    IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex, bool force, const SQChar * comment);

    /* --------------------------------------------------------------------------------------------
     * Add or update a double value.
    */
    IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value)
    {
        return SetFloat(section, key, value, false, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a double value.
    */
    IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value, bool force)
    {
        return SetFloat(section, key, value, force, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a double value.
    */
    IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value, bool force, const SQChar * comment);

    /* --------------------------------------------------------------------------------------------
     * Add or update a double value.
    */
    IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value)
    {
        return SetBoolean(section, key, value, false, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a double value.
    */
    IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value, bool force)
    {
        return SetBoolean(section, key, value, force, nullptr);
    }

    /* --------------------------------------------------------------------------------------------
     * Add or update a boolean value.
    */
    IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value, bool force, const SQChar * comment);

    /* --------------------------------------------------------------------------------------------
     * Delete an entire section, or a key from a section.
    */
    bool DeleteValue(const SQChar * section)
    {
        return DeleteValue(section, nullptr, nullptr, false);
    }

    /* --------------------------------------------------------------------------------------------
     * Delete an entire section, or a key from a section.
    */
    bool DeleteValue(const SQChar * section, const SQChar * key)
    {
        return DeleteValue(section, key, nullptr, false);
    }

    /* --------------------------------------------------------------------------------------------
     * Delete an entire section, or a key from a section.
    */
    bool DeleteValue(const SQChar * section, const SQChar * key, const SQChar * value)
    {
        return DeleteValue(section, key, value, false);
    }

    /* --------------------------------------------------------------------------------------------
     * Delete an entire section, or a key from a section.
    */
    bool DeleteValue(const SQChar * section, const SQChar * key, const SQChar * value, bool empty);
};

} // Namespace:: SqMod