//
//  File:   hzChain.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 hzChain_h
#define hzChain_h
#include <iostream>
#include <fstream>
#include <stdarg.h>
#include "hzBasedefs.h"
#include "hzString.h"
#include "hzTmplArray.h"
class   hzEmaddr ;
class   hzIpaddr ;
/*
**  Section 2:  The hzChain class
*/
class   hzChain
{
    //  Category:   Data
    //
    //  hzChain is an unlimited char buffer, for any purpose but widely used to assemble complex string values such as HTTP server responses. To this end, hzChain has both standard
    //  append functions and Printf, a vararg printf type member function. String assembly must be as a series of one or more append operations as no INSERT method is provided. The
    //  content is held in a double linked list of fixed sized blocks rather than as contiguous memory. This arrangement avoids reallocation and copying during string assembly, but
    //  not if a hzChain of more than one block is cast to a null terminated character string. Such casting however, is not the norm. hzChain instances are expected to be iterated
    //  from begining to end. An iterator is provided as a sub-class for this purpose.
    //
    //  Although the double linked list allows iterators to decrement, this facility is not used in any current HadronZoo software and should be considered as deprecated.
    //
    //  In addition to acting as a single string value container, hzChain allows blocks to be deleted from the front, making it suitable for processing data streams. Incomming data
    //  and requests from connected clients and server responses, are both processed as data streams by the hzIpServer class. Once the iterator processing the incomming data passes
    //  onto the next block, the first block is discarded. Likewise once blocks in the outgoing data have been written to the socket, they are discarded. Doing this prevents chains
    //  becoming ever larger in cases where clients remain connected and make a large number of requests.
    //
    //  Note that while hzChain is good for string assembly, the fixed block size makes it a poor choice for string storage. Once assembled, strings should be stored as hzString.
    struct _chain
    {
        //  hzChain control area
        void*       m_Test ;            //  For corruption testing
        void*       m_Begin ;           //  Address of first block in chain
        void*       m_End ;             //  Address of last block in chain
        uint32_t    m_nSize ;           //  Total size in bytes
        int16_t     m_copy ;            //  Copy count
        int16_t     m_resv ;            //  Reserved
        _chain  (void) ;
        ~_chain (void) ;
    } ;
    _chain*     mx ;    //  Smart pointer to contents
    int32_t     _compare    (const hzChain& op) const ;
public:
    struct  BlkIter
    {
        //  Block iterator used for writing out whole chains to sockets
        void*   m_block ;       //  Current block address
        BlkIter (void)  { m_block = 0 ; }
        //  Operators to set iterator position
        BlkIter&    operator=    (const hzChain& I)
        {
            //  Set a block iterator current block pointer to the current block in the chain
            if (I.mx)
                m_block = I.mx->m_Begin ;
            else
                m_block = 0 ;
            return *this ;
        }
        BlkIter&    operator=    (const BlkIter& I)
        {
            //  Set this block iterator to another
            m_block = I.m_block ;
            return *this ;
        }
        //  Advance the block
        BlkIter&    Advance (void) ;
        //  Advance the block and remove previous
        BlkIter&    Roll    (void) ;
        //  Return block internals, data and data size
        void*       Data    (void) ;
        uint32_t    Size    (void) ;
    } ;
    struct  Iter
    {
        //  Standard bytewise chain iterator
        void*       m_block ;       //  Current block address
        uint32_t    m_nLine ;       //  For tracking line numbers
        uint32_t    m_nCol ;        //  Column number
        uint16_t    m_nOset ;       //  Current offset within block
        char        m_cDefault ;    //  Default char
        char        m_Reserved ;    //  Not used at present
        Iter    (void)
        {
            //  Construct and init the chain iterator
            m_block = 0 ;
            m_nLine = 1 ;
            m_nCol = 0 ;
            m_nOset = 0 ;
            m_cDefault = 0 ;
        }
        //  Read unicode char
        hzEcode ReadUnicodeChar (uint32_t& uniVal) ;
        //  Skip whitespace
        Iter&       Skipwhite   (void) ;
        //  Misc functions
        uint32_t    Line    (void)          { return m_nLine ; }
        uint32_t    Col     (void)          { return m_nCol ; }
        void        Line    (uint32_t n)    { m_nLine = n ; }
        char    current     (void) const ;
        bool    eof         (void) const ;
        //  Operators to set iterator position
        Iter&   operator=    (const hzChain& I)
        {
            //  Set this chain iterator to the start of the supplied chain
            if (I.mx)
                m_block = I.mx->m_Begin ;
            else
                m_block = 0 ;
            m_nLine = 1 ;
            m_nCol = 0 ;
            m_nOset = 0 ;
            return *this ;
        }
        Iter&   operator=    (const Iter& I)
        {
            //  Set this chain iterator to another chain iterator
            m_block = I.m_block ;
            m_nLine = I.m_nLine ;
            m_nOset = I.m_nOset ;
            m_cDefault = I.m_cDefault ;
            return *this ;
        }
        //  Write out block of chars to hzChain, uchar or char buffer. Return bytes written out but don't increment iterator (do that in app with the return value)
        uint32_t    Write   (void* pBuf, uint32_t maxBytes) ;
        //uint32_t  Write   (hzString& str, uint32_t maxBytes) ;
        bool    operator==   (const Iter& I) const  { return m_block == I.m_block && m_nOset == I.m_nOset ? true : false ; }
        bool    operator!=   (const Iter& I) const  { return m_block == I.m_block && m_nOset == I.m_nOset ? false : true ; }
        //  Advance (increment without column/line accounting)
        uint32_t    Advance     (uint32_t nInc) ;
        //  Increment and decrement
        Iter&   operator++  (void) ;
        Iter&   operator++  (int) ;
        Iter&   operator--  (void) ;
        Iter&   operator--  (int) ;
        Iter&   operator+=  (uint32_t nInc) ;
        Iter&   operator-=  (uint32_t nDec) ;
        //  Case sensitive compare functions
        bool    Equal       (const char c) const ;
        bool    Equal       (const char* s) const ;
        bool    Equal       (const hzString& S) const   { return Equal(*S) ; }
        //  Case in-sensitive compare functions
        bool    Equiv       (const char c) const ;
        bool    Equiv       (const char* s) const ;
        bool    Equiv       (const hzString& S) const   { return Equiv(*S) ; }
        //  Compare operators
        bool    operator==  (const char c) const    { return Equal(c) ; }
        bool    operator==  (const char* s) const   { return Equal(s) ; }
        bool    operator==  (hzString& S) const     { return Equal(S) ; }
        bool    operator==  (Iter& I) const         { return m_block == I.m_block && m_nOset == I.m_nOset ? true : false ; }
        bool    operator!=  (const char c) const    { return !Equal(c) ; }
        bool    operator!=  (const char* s) const   { return !Equal(s) ; }
        bool    operator!=  (hzString& S) const     { return !Equal(S) ; }
        bool    operator!=  (Iter& I) const         { return m_block == I.m_block && m_nOset == I.m_nOset ? false : true ; }
        //  Get current or offset char
        char    operator[]  (uint32_t nOset) const ;
        char    operator*   (void) const ;
    } ;
    void    Clear   (void) ;
    //  Constructors/Destructors
    hzChain     (void) ;
    hzChain     (const hzChain& op) ;
    ~hzChain    (void) ;
    //  Internal use only
    void*   _int_addr   (void) const        { return mx ; }
    void    _int_set    (const void* ptr)   { mx = (_chain*) ptr ; }
    void    _int_clr    (void)              { mx = 0 ; }
    //  Get hzChain attributes
    uint32_t    Size    (void) const    { return mx ? mx->m_nSize : 0 ; }
    uint32_t    Copies  (void) const    { return mx ? mx->m_copy : 0 ; }
    //uint16_t  GetID   (void) const    { return mx ? mx->m_Id : 0xffff ; }
    //  Set chain contents
    hzChain&    operator=   (const hzChain& op) ;
    hzChain&    operator=   (const hzString& S) ;
    hzChain&    operator=   (const char* pStr) ;
    //  Test operator
    bool        operator!   (void)  { return Size() > 0 ? false : true ; }
    //  Append void* data to the chain. Note as there is no null termination the number of bytes to append must be specified.
    uint32_t    Append      (const void* vpBuf, uint32_t nBytes) ;
    //  Append a sub-chain
    uint32_t    AppendSub   (hzChain& Z, uint32_t nStart, uint32_t nBytes) ;
    //  Append single character
    hzEcode     AddByte     (const char c) ;
    //  Append using varargs
    uint32_t    _vainto     (const char*, va_list) ;
    uint32_t    Printf      (const char* ...) ;
    //  Append whole entities by operators
    hzChain&    operator+=  (const char* s) ;
    hzChain&    operator+=  (const hzString& s) ;
    hzChain&    operator+=  (const hzChain& op) ;
    hzChain&    operator+=  (std::ifstream& ifs) ;
    hzChain&    operator<<  (const char* s) ;
    hzChain&    operator<<  (const hzString& s) ;
    hzChain&    operator<<  (const hzEmaddr& e) ;
    hzChain&    operator<<  (const hzIpaddr& i) ;
    hzChain&    operator<<  (uint32_t nValue) ;
    hzChain&    operator<<  (uint64_t nValue) ;
    hzChain&    operator<<  (int32_t nValue) ;
    hzChain&    operator<<  (int64_t nValue) ;
    hzChain&    operator<<  (double nValue) ;
    hzChain&    operator<<  (const hzChain& op) ;
    hzChain&    operator<<  (std::ifstream& is) ;
    //  Compare operators
    bool    operator==  (const hzChain& op) const   { return _compare(op) == 0 ? true : false ; }
    bool    operator!=  (const hzChain& op) const   { return _compare(op) != 0 ? true : false ; }
    bool    operator<   (const hzChain& op) const   { return _compare(op) <  0 ? true : false ; }
    bool    operator<=  (const hzChain& op) const   { return _compare(op) <= 0 ? true : false ; }
    bool    operator>   (const hzChain& op) const   { return _compare(op) >  0 ? true : false ; }
    bool    operator>=  (const hzChain& op) const   { return _compare(op) >= 0 ? true : false ; }
    //  Stream operators
    friend  std::istream&   operator>>  (std::istream& is, hzChain& obj) ;
    friend  std::ostream&   operator<<  (std::ostream& os, const hzChain& obj) ;
} ;
#define chIter   hzChain::Iter
#define chMark   hzChain::Mark
//  Global null chain
extern  hzChain _hz_null_hzChain ;
#endif  //  hzChain_h