/*!
  @file         IOMan_KernelPages.hpp
  @author       TorstenS
  @ingroup      IOManagement
  @brief        This module is used to define and implement an class which 
                handles a collection of pages, whereby all pages have he same 
                properties, i.e there are from the same page type.

                The class IOMan_IKernelPagesIterator defines and implements 
                an iterator on the above mentioned class, which offers the
                facility to access the stored pages in a common way as a
                Kernel_IPage. The iterator returns the stored pages in
                the temporal sequence of there storage( FIFO).
                The template class IOMan_Pages is used to store a concrete 
                collection of pages. This class is responsible to get the 
                page type individual memory for the page handler. The above
                mentioned class IOMan_KernelIPages deals with structures
                pointing into this class. Note that there is a very tight 
                connection between IOMan_KernelIPages and IOMan_Pages.
                The template class IOMan_PagesIterator defines and implements 
                an iterator on the above mentioned class, which offers the
                facility to access the stored pages in a concrete way for 
                example as data, log or converter pages.The iterator returns 
                the stored pages in the temporal sequence of there storage( FIFO).

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

\endif
*/


#ifndef IOMAN_KERNELPAGES_HPP
#define IOMAN_KERNELPAGES_HPP



/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "gsp00.h"

#include "Container/Container_Vector.hpp"
#include "KernelCommon/Kernel_Common.hpp"
#include "KernelCommon/Kernel_IPage.hpp"
#include "RunTime/MemoryManagement/RTEMem_AllocatorWrapper.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/

/// Defines index of the first page within page collection

#define IOMAN_FIRST_INDEX           0

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/


/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

// forward declaraion

class IOMan_IKernelPagesIterator;
template <class PAGE> class IOMan_PagesIterator;


/* -----------------------------------------------------------------------*/
/*!
  @interface    IOMan_IKernelPages
  @brief        This module is used to define and implement an class which 
                handles a collection of pages, whereby all pages have he same 
                properties, i.e there are from the same page type.
 */
/* -----------------------------------------------------------------------*/


class IOMan_IKernelPages
{
    friend class IOMan_IKernelPagesIterator;
public:

    /* -----------------------------------------------------------------------*/
    /*! @name Common container access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to clear the current page set, i.e the 
                internal counters of this class are reinitialized and the
                destructors of the stored pages are called! Furthermore no
                memory allocated before with the given allocator is released.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Clear()
    {
        m_KernelPageList.Clear();
        m_FramePtrList.Clear();
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to get a pointer onto a list of pointers
                containing the addresses of the page frames(!) and not the 
                page handler managed by this page set. if no index is given
                than the full list is returned else the index identifies the
                start offset of the returned pointer list. Note that he index 
                one  specifies the second item within the page set.
       @return  tsp00_PageAddr* of the first page frame.
     */
    /* -----------------------------------------------------------------------*/

    tsp00_PageAddr* GetFrameList( SAPDB_UInt Index = IOMAN_FIRST_INDEX )
    {
        SAPDBERR_ASSERT_STATE( Index <= ( GetPageCount() -1 ) );

        return( REINTERPRET_CAST( tsp00_PageAddr*, &m_FramePtrList[ Index ] ));
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to get the current number of stored pages.
       @return  Page count
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_UInt GetPageCount() const
    {
        return( m_KernelPageList.GetSize() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to check whether the page set is empty.
       @return  true if page set is empty; else false.
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool IsEmpty() const
    {
        return( m_KernelPageList.IsEmpty() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to check whether the page set is able to
                store another page.
       @return  true if the maximum capacity is reached; else false.
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool IsFull() const
    {
        return( m_KernelPageList.IsFull() );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

protected:

    /* -----------------------------------------------------------------------*/
    /*! @name Protected constructors and initialization */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The internal member data are initialized, but no memory is
                allocated with the given allocator. This will be done with the
                method Initialize.
       @param   Allocator [in] Allocator
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    IOMan_IKernelPages( SAPDBMem_IRawAllocator  &Allocator )
    :
    m_KernelPageList( Allocator ),
    m_FramePtrList( Allocator ){}

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to initialize the page set, i.e to get
                the memory for pages and the frame pointer list via the 
                given allocator.
       @param   MaxPages [in] Capacity of the page set
       @return  true if the initialization is succesful; else false
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool Initialize( const SAPDB_Int2  MaxPages )
    {
        if(! m_KernelPageList.Reserve( MaxPages ))
            return( false );

        if(! m_FramePtrList.Reserve( MaxPages ))
        {
            Delete();
            return( false );
        }
        return( true );
    }
    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The destructor will release all memory allocated before with
                the given allocator and will call the destructors of the 
                pages stored within the page set.
       @return  none.
     */
    /* -----------------------------------------------------------------------*/

    ~IOMan_IKernelPages()
    {
        Delete();
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to delete all internal structures and
                to deallocate the memory.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Delete()
    {
        m_KernelPageList.Delete();
        m_FramePtrList.Delete();
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Common access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to insert another page into the page set.
                The insertion sequence is the sequence in which the pages are 
                stored within the collection and therefore the sequence in which 
                an iterator operates on this set. The caller has to ensure that 
                the container is not full. Note that at least the destructor 
                of this class or the clear method will call the destructor for 
                each stored page.
       @param   Page [in] Page quantified for I/O management
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Add( Kernel_IPage  &Page )
    {
        SAPDBERR_ASSERT_STATE( !IsFull() );

        m_KernelPageList.InsertEnd( &Page );
        m_FramePtrList.InsertEnd( Page.GetFramePtr() );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

private:

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Collection of pages of one page type.
     */
    /* -----------------------------------------------------------------------*/

    Container_Vector<Kernel_IPage*>  m_KernelPageList;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Collection of the pure page frame pointer of the pages 
                handled by m_PageList. Each item of the m_FramePtrList 
                corresponds with an item in the m_PageList collection.
     */
    /* -----------------------------------------------------------------------*/

    Container_Vector<Kernel_IPage::PageFramePtr>    m_FramePtrList;
};

/* -----------------------------------------------------------------------*/
/*!
   @interface   IOMan_IKernelPagesIterator
   @brief       The class IOMan_IKernelPagesIterator defines and implements 
                an iterator on the above mentioned class, which offers the
                facility to access the stored pages in a common way as a
                Kernel_IPage. The iterator returns the stored pages in the 
                temporal sequence of there storage( FIFO).
 */
/* -----------------------------------------------------------------------*/

class IOMan_IKernelPagesIterator
{
public:

    /* -----------------------------------------------------------------------*/
    /*! @name Constructors and initialization */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   Constructor
       @param   Pages [in] Collection of pages
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    IOMan_IKernelPagesIterator( IOMan_IKernelPages   &Pages )
    :m_Pages( Pages ),
     m_Index(IOMAN_FIRST_INDEX)
    {}

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Iterator access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to make the first page (index = 0) within 
                the set to the current page for the iterator. If an index is 
                given this index identifies the page which will be the first 
                one. There is no check whether the page is valid.
       @param   Index [in] Offset of the first page. Default is zero.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Begin( const SAPDB_UInt  Index = IOMAN_FIRST_INDEX )
    {
        m_Index = Index;
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to report whether the current page 
                pointed by the iterator is valid.
       @return  true means that the current page is not valid and that the end
                of the page set is reached; else false
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool End() const
    {
        return( m_Index >= m_Pages.GetPageCount() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to set the iterator to the next page within
                the page collection.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void operator++()
    {
        ++m_Index;
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to get access to the page pointed by the
                iterator.
       @return  (Kernel_IPage&amp;)
     */
    /* -----------------------------------------------------------------------*/

    Kernel_IPage& operator*()
    {
        return( *m_Pages.m_KernelPageList[ m_Index ] );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

private:

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Reference of the page collection this iterator works on.
     */
    /* -----------------------------------------------------------------------*/

    IOMan_IKernelPages   &m_Pages;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Index within the page collection administrated by the class
                IOMan_IKernelPages
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_UInt  m_Index;
};


/* -----------------------------------------------------------------------*/
/*!
  @class    IOMan_Pages
  @brief    The template class IOMan_Pages is used to store a concrete 
            collection of pages. This class is responsible to get the 
            page type individual memory for the page handler. The above
            mentioned class IOMan_KernelIPages deals with structures
            pointing into this class. Note that there is a very tight 
            connection between IOMan_KernelIPages and IOMan_Pages.
 */
/* -----------------------------------------------------------------------*/

template <class PAGE>
class IOMan_Pages : public IOMan_IKernelPages
{

    /// Define PageIterator as a friend
    friend class IOMan_PagesIterator<PAGE>;

public:

    /* -----------------------------------------------------------------------*/
    /*! @name Constructors and initialization */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The internal member data are initialized, but no memory is
                allocated with the given allocator. This will be done with the
                method Initialize.
       @param   Allocator [in] Allocator
       @param   Identifier [in] Identifier for the given allocator to support
                                memory allocation monitoring
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    IOMan_Pages(
        SAPDBMem_IRawAllocator  &Allocator,
        SAPDB_UTF8              *Identifier )
    :
    m_Allocator( Identifier, Allocator ),
    IOMan_IKernelPages( m_Allocator ),
    m_PageList( m_Allocator ){}

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to initialize the page set, i.e to get
                the memory for pages and the frame pointer list via the 
                given allocator.
       @param   MaxPages [in] Capacity of the page set
       @return  true if the initialization is succesful; else false
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool Initialize( const SAPDB_Int2  MaxPages )
    {
        if(! m_PageList.Reserve( MaxPages ))
            return( false );

        if(! IOMan_IKernelPages::Initialize( MaxPages ))
        {
            Delete();
            return( false );
        }
        return( true );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The destructor will release all memory allocated before with
                the given allocator and will call the destructors of the 
                pages stored within the page set.
       @return  none.
     */
    /* -----------------------------------------------------------------------*/

    ~IOMan_Pages()
    {
        Delete();
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to delete all internal structures and
                to deallocate the memory.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Delete()
    {
        IOMan_IKernelPages::Delete();
        m_PageList.Delete();
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Common Acccess */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to insert another page into the page set.
                The insertion sequence is the sequence in which the pages are 
                stored within the collection and therefore the sequence in which 
                an iterator operates on this set. The caller has to ensure that 
                the container is not full. Note that at least the destructor 
                of this class or the clear method will call the destructor for 
                each stored page.
       @param   Page [in] Page quantified for I/O management
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Add( PAGE  &Page )
    {
        SAPDBERR_ASSERT_STATE( !IsFull() );

        m_PageList.InsertEnd( Page );

        // Danger: Give the copied page handler to this method and not the
        // given page handler!
        IOMan_IKernelPages::Add( *m_PageList.Position( m_PageList.GetSize() -1) );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to clear the current page set, i.e the 
                internal counters of this class are reinitialized and the
                destructors of the stored pages are called! Furthermore no
                memory allocated before with the given allocator is released.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    void Clear()
    {
        m_PageList.Clear();
        IOMan_IKernelPages::Clear();
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

private:

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Base allocator used for all dependent memory allocation of
                this template class. Note that this member data has to be the
                first member data defined in this class, because the sequence
                of the execution of the initialization lists depends on it!
     */
    /* -----------------------------------------------------------------------*/

    RTEMem_AllocatorWrapper  m_Allocator;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Collection of pages of one page type.
     */
    /* -----------------------------------------------------------------------*/

    Container_Vector<PAGE>  m_PageList;
};


/* -----------------------------------------------------------------------*/
/*!
   @class   IOMan_PagesIterator
   @brief   The template class IOMan_PagesIterator defines and implements 
            an iterator on the above mentioned class, which offers the
            facility to access the stored pages in a concrete way for 
            example as data, log or converter pages. The iterator returns 
            the stored pages in the temporal sequence of there storage( FIFO).
 */
/* -----------------------------------------------------------------------*/


template <class PAGE>
class IOMan_PagesIterator
{
public:

    /* -----------------------------------------------------------------------*/
    /*! @name Constructors and initialization */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   Constructor
       @param   Pages [in] Collection of pages
       @return  none
     */
    /* -----------------------------------------------------------------------*/


    IOMan_PagesIterator( IOMan_Pages<PAGE>  &Pages )
    :m_Pages( Pages ),
     m_Index(IOMAN_FIRST_INDEX)
    {}

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Iterator access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to make the first page (index = 0) within 
                the set to the current page for the iterator. If an index is 
                given this index identifies the page which will be the first 
                one. There is no check whether the page is valid.
       @param   Index [in] Offset of the first page. Default is zero.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    virtual void Begin( const SAPDB_UInt  Index = IOMAN_FIRST_INDEX )
    {
        m_Index = Index;
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to report whether the current page 
                pointed by the iterator is valid.
       @return  true means that the current page is not valid and that the end
                of the page set is reached; else false
     */
    /* -----------------------------------------------------------------------*/

    virtual SAPDB_Bool End() const
    {
        return( m_Index >= m_Pages.GetPageCount() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to set the iterator to the next page within
                the page collection.
       @return  none
     */
    /* -----------------------------------------------------------------------*/

    virtual void operator++()
    {
        ++m_Index;
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to get access to the page pointed by the
                iterator.
       @return  (PAGE*)
     */
    /* -----------------------------------------------------------------------*/

    PAGE& operator*() const
    {
        return( m_Pages.m_PageList[ m_Index ] );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

private:

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Reference of the page collection this iterator works on. 
     */
    /* -----------------------------------------------------------------------*/

    IOMan_Pages<PAGE>  &m_Pages;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Index within the page collection administrated by the class
                IOMan_Pages
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_UInt  m_Index;
};

#endif  /* IOMAN_KERNELPAGES_HPP */
