/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_STRING_H
#define ECXX_CTL_STRING_H


#include <eCxx/CTL/AlignedStorage.h>
#include <eCxx/CTL/Utility.h>


namespace eCxx {


//
// A simple string
//
// WARNING : All functions that accept 'PGMCharPointer' and 'PGMCharPointerFar' as their parameters
//           expect the pointers to come from program memory exclusively!
//
// NOTE    : Whenever possible, use the near program pointer because the far one has more overhead
//           and restrictions.
//
template <size_t MaxCapacity>
class String {
    public:
        typedef       char   ValueType;
        typedef       size_t SizeType;

        typedef       char&  Reference;
        typedef const char&  ConstReference;

        typedef       char*  Pointer;
        typedef const char*  ConstPointer;

        typedef       char*  Iterator;
        typedef const char*  ConstIterator;

        static constexpr SizeType ValueSize = sizeof(ValueType);
        static constexpr SizeType Capacity  = MaxCapacity;

    public:
        inline String() noexcept;
        inline String(const String& string) noexcept;
        inline String(String&& string) noexcept;

        template <size_t OtherMaxCapacity> inline String(const String<OtherMaxCapacity>& string) noexcept;
        template <size_t OtherMaxCapacity> inline String(String<OtherMaxCapacity>&& string) noexcept;

        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String(PGMCharPointer    ptr) noexcept;
        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String(PGMCharPointerFar ptr) noexcept;

        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String(PGMCharPointer    ptr, SizeType lenMax) noexcept;
        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String(PGMCharPointerFar ptr, SizeType lenMax) noexcept;

        inline ~String() noexcept;

        inline String& operator=(const String& string) noexcept;
        inline String& operator=(String&& string) noexcept;

        template <size_t OtherMaxCapacity> inline String& operator=(const String<OtherMaxCapacity>& string) noexcept;
        template <size_t OtherMaxCapacity> inline String& operator=(String<OtherMaxCapacity>&& string) noexcept;

        inline SizeType capacity() const noexcept;
        inline SizeType size() const noexcept;
        inline SizeType length() const noexcept;

        inline bool empty() const noexcept;
        inline void clear() noexcept;
        inline void resize(SizeType length, ValueType fill = '\0') noexcept;

        inline String& operator--() noexcept;
        inline String& operator--(int) noexcept = delete;

        inline String& operator+=(ValueType chr) noexcept;
        inline String& operator+=(const String& string) noexcept;
        inline String& operator+=(String&& string) noexcept;

        template <size_t OtherMaxCapacity> inline String& operator+=(const String<OtherMaxCapacity>& string) noexcept;
        template <size_t OtherMaxCapacity> inline String& operator+=(String<OtherMaxCapacity>&& string) noexcept;

        template <typename PGMPointerT, typename PGMStrNCpyFunctorT>
        inline String& _concatWith(PGMPointerT ptr, SizeType lenMax) noexcept;

        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String& concatWith(PGMCharPointer    ptr, SizeType lenMax) noexcept;
        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String& concatWith(PGMCharPointerFar ptr, SizeType lenMax) noexcept;

        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String& concatWith(PGMCharPointer    ptr) noexcept;
        template <typename PGMStrNCpyFunctorT = PGMStrNCpy> inline String& concatWith(PGMCharPointerFar ptr) noexcept;

        inline bool operator==(const String& string) const noexcept;
        inline bool operator!=(const String& string) const noexcept;

        template <size_t OtherMaxCapacity> inline bool operator==(const String<OtherMaxCapacity>& string) const noexcept;
        template <size_t OtherMaxCapacity> inline bool operator!=(const String<OtherMaxCapacity>& string) const noexcept;

        template <typename PGMPointerT, typename PGMStrNCmpFunctorT, typename PGMStrNLenFunctorT>
        inline bool _equalsTo(PGMPointerT ptr, SizeType lenMax) const noexcept;

        template <typename PGMStrNCmpFunctorT = PGMStrNCmp, typename PGMStrNLenFunctorT = PGMStrNLen>
        inline bool equalsTo(PGMCharPointer ptr, SizeType lenMax) const noexcept;

        template <typename PGMStrNCmpFunctorT = PGMStrNCmp, typename PGMStrNLenFunctorT = PGMStrNLen>
        inline bool equalsTo(PGMCharPointerFar ptr, SizeType lenMax) const noexcept;

        template <typename PGMStrNCmpFunctorT = PGMStrNCmp, typename PGMStrNLenFunctorT = PGMStrNLen>
        inline bool equalsTo(PGMCharPointer ptr) const noexcept;

        template <typename PGMStrNCmpFunctorT = PGMStrNCmp, typename PGMStrNLenFunctorT = PGMStrNLen>
        inline bool equalsTo(PGMCharPointerFar ptr) const noexcept;

        inline ConstPointer cStr() noexcept;

        inline ConstPointer data() const noexcept;

        inline Reference front() noexcept;
        inline ConstReference front() const noexcept;

        inline Reference back() noexcept;
        inline ConstReference back() const noexcept;

        inline Reference operator[] (SizeType index) noexcept;
        inline ConstReference operator[] (SizeType index) const noexcept;

        inline Iterator begin() noexcept;
        inline Iterator end() noexcept;

        inline ConstIterator cbegin() const noexcept;
        inline ConstIterator cend() const noexcept;

    private:
        template <size_t OtherMaxCapacity>
        friend struct StringHelper;

        friend class Convert;

        inline SizeType& _writeableLength() noexcept
        { return _length; }

        inline Pointer _writeableData() noexcept
        { return _buffer(0); }

    private:
        SizeType                                _length;
        AlignedStorage<ValueType, Capacity + 1> _buffer; // +1 for the C-style string null terminator
};


//
// Include the implementation file
//
#define INCLUDE_ECXX_CTL_STRING_TPP
#include "String.tpp"


} // namespace eCxx


#endif
