/* -*- C++ -*- vim: set syntax=cpp: */
#ifndef  __QUEX_INCLUDE_GUARD__BUFFER__FILLER__BUFFER_FILLER
#define  __QUEX_INCLUDE_GUARD__BUFFER__FILLER__BUFFER_FILLER

#include <quex/code_base/definitions>
#include <quex/code_base/buffer/Buffer>
#include <quex/code_base/buffer/loader/ByteLoader>

QUEX_NAMESPACE_MAIN_OPEN

struct QUEX_NAME(Converter_tag);
struct QUEX_NAME(Buffer_tag);

typedef struct QUEX_SETTING_USER_CLASS_DECLARATION_EPILOG QUEX_NAME(BufferFiller_tag) {
    /* This is the interface that the buffer sees of the buffer filler. Its
     * task is to coordinate the filling of buffer content from a stream in the
     * background. Some fillers may convert characters or filter.  All fillers
     * must provide functions for the following pointers. The pointers are set
     * with the function
     *
     *              BufferFiller_setup(...) 
     *
     * which shall be called in any '_construct' function of a filler. Note,
     * that filler types shall inherit this class. This means, that the first
     * element of the derived struct is to be of this type and best called
     * 'base'.  For example, please, consider the 'plain' and 'iconv'
     * implementations in the correspondent sub directories.                 */
    E_Ownership               ownership;

    QUEX_NAME(ByteLoader)*    byte_loader;

    /* -- 'Tell': Character index of the next character to be loaded into
     *            the buffer, when 'derived.load_characters()' is called.
     *                                                                       */
    QUEX_TYPE_STREAM_POSITION   
                (*input_character_tell)(struct QUEX_NAME(BufferFiller_tag)*);

    /* -- 'Seek': Sets the character index of the next character to be loaded
     *            into the buffer, when 'derived.load_characters()' is 
     *            called.
     *                                                                       */
    bool        (*input_character_seek)(struct QUEX_NAME(BufferFiller_tag)*,
                                        const QUEX_TYPE_STREAM_POSITION Index);

    /* -- 'Stomach Byte Number': is the number of bytes that have been read
     *                           from the stream but not yet converted.      
     *                                                                       */
    ptrdiff_t   (*stomach_byte_n)(struct QUEX_NAME(BufferFiller_tag)*);

    /* -- 'Clear': Undo any internal state-dependency. Conversion or what-
     *             soever starts from a clean page.   
     *                                                                       */
    void        (*stomach_clear)(struct QUEX_NAME(BufferFiller_tag)*);       
                                                                             
    /* -- 'Delete Operator': There are derived 'classes' from this one. User 
     *                  only stores a pointer to BufferFiller, and requires a 
     *                  way to delete the whole object.
     *                                                                       */
    void        (*delete_self)(struct QUEX_NAME(BufferFiller_tag)*);         
                                                                             
                                                                             
    /* -- byte order (i.e little- vs. big-endian) reversion: enable/disable
     *    the reversion of byte order.    
     *                                                                       */
    bool                      _byte_order_reversion_active_f;

    QUEX_TYPE_STREAM_POSITION character_index_next_to_fill;

    /* Byte number per character. If != -1 => there is a linear relationship
     *                            between character position and character
     *                            index.                                     */
    ptrdiff_t                 byte_n_per_character;

    struct {
        /* PASSIVE API: Lexical analyzer requests BufferFiller to fill its
         *              buffer.                                              */

        /* -- 'Read' reads N characters from a stream into a buffer 
         * (independent of their size)                                       */
        size_t      (*load_characters)(struct QUEX_NAME(BufferFiller_tag)*,
                                       QUEX_TYPE_CHARACTER* memory, 
                                       const size_t         N,
                                       bool*                end_of_stream_f);

        /* ACTIVE: User fills the buffer manually                                
         *
         * To be implemented by the derived class ...                        */
        void        (*fill_prepare)(struct QUEX_NAME(BufferFiller_tag)*  me,
                                    QUEX_TYPE_CHARACTER*                 RegionBeginP,
                                    QUEX_TYPE_CHARACTER*                 RegionEndP,
                                    void**                               begin_p,
                                    const void**                         end_p);
        ptrdiff_t   (*fill_finish)(struct QUEX_NAME(BufferFiller_tag)* me,
                                   QUEX_TYPE_CHARACTER*                BeginP,
                                   const QUEX_TYPE_CHARACTER*          EndP,
                                   const void*                         FilledEndP);

        /* destruct_self: Free resources occupied by 'me' BUT NOT 'myself'.
         * delete_self:   Free resources occupied by 'me' AND 'myself'.      */
        void        (*destruct_self)(struct QUEX_NAME(BufferFiller_tag)*);
    } derived;
} QUEX_NAME(BufferFiller);

QUEX_INLINE QUEX_NAME(BufferFiller)*
QUEX_NAME(BufferFiller_new)(QUEX_NAME(ByteLoader)*                      byte_loader, 
                            struct QUEX_NAME(Converter_tag)* converter,
                            const size_t                     TranslationBufferMemorySize);

QUEX_INLINE QUEX_NAME(BufferFiller)* 
QUEX_NAME(BufferFiller_new_DEFAULT)(QUEX_NAME(ByteLoader)*  byte_loader, 
                                    const char*             InputCodecName);

QUEX_INLINE void    
QUEX_NAME(BufferFiller_setup)(QUEX_NAME(BufferFiller)*   me,
                              size_t       (*read_characters)(QUEX_NAME(BufferFiller)*,
                                                              QUEX_TYPE_CHARACTER*, 
                                                              const size_t, 
                                                              bool*),
                              ptrdiff_t    (*stomach_byte_n)(QUEX_NAME(BufferFiller)*),
                              void         (*stomach_clear)(QUEX_NAME(BufferFiller)*),
                              void         (*destruct_self)(QUEX_NAME(BufferFiller)*),
                              void         (*derived_fill_prepare)(QUEX_NAME(BufferFiller)*  me,
                                                                   QUEX_TYPE_CHARACTER*      RegionBeginP,
                                                                   QUEX_TYPE_CHARACTER*      RegionEndP,
                                                                   void**                    begin_p,
                                                                   const void**              end_p),
                              ptrdiff_t    (*derived_fill_finish)(QUEX_NAME(BufferFiller)*   me,
                                                                  QUEX_TYPE_CHARACTER*       BeginP,
                                                                  const QUEX_TYPE_CHARACTER* EndP,
                                                                  const void*                FilledEndP),
                              QUEX_NAME(ByteLoader)*  byte_loader, 
                              ptrdiff_t               ByteNPerCharacter);

QUEX_INLINE ptrdiff_t  
    QUEX_NAME(BufferFiller_load)(QUEX_NAME(BufferFiller)*   me, 
                                 QUEX_TYPE_CHARACTER*       RegionBeginP, 
                                 const ptrdiff_t            Size,
                                 QUEX_TYPE_STREAM_POSITION  CharacterIndexBegin,
                                 bool*                      end_of_stream_f);

QUEX_INLINE void    
    QUEX_NAME(BufferFiller_reset)(QUEX_NAME(BufferFiller)* me, 
                                  QUEX_NAME(ByteLoader)*              new_byte_loader);

QUEX_INLINE void       
    QUEX_NAME(BufferFiller_character_index_reset)(QUEX_NAME(BufferFiller)* me);

QUEX_NAMESPACE_MAIN_CLOSE

#include <quex/code_base/buffer/filler/BufferFiller_Converter>
#include <quex/code_base/buffer/filler/BufferFiller_Plain>

#endif /* __QUEX_INCLUDE_GUARD__BUFFER__BUFFERFILLER */
