/*!**************************************************************************

  module      : Log_BeforeImage.hpp
  special area: Logging
  responsible : UweH
  last changed: 2000-09-25  12:00
  copyright:    (c) 2000-2004 SAP AG
  description : defines classes Log_BeforeImage, Log_UndoPage, Log_BeforeImageSpace



    ========== licence begin  GPL
    Copyright (c) 2000-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


*****************************************************************************/


#ifndef Log_BeforeImage_H
#define Log_BeforeImage_H

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


#include "SAPDBCommon/SAPDB_Types.hpp"
#include "KernelCommon/Kernel_VTrace.hpp"
#include "DataAccess/Data_ISplitSpace.hpp"
#include "DataAccess/Data_SplitSpace.hpp"
#include "DataAccess/Data_PageSplitSpace.hpp"
#include "Logging/Log_Types.hpp"
#include "Logging/Log_IImage.hpp"
#include "ggg91.h"

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/
/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/
/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/
/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/
class Log_UndoPage;
/*! --------------------------------------------------------------------------------
declaration: Log_BeforeImageSpace
*/
typedef Data_SplitSpace<Log_UndoPage> Log_BeforeImageSpace;
/*! endDeclaration: */

/*! --------------------------------------------------------------------------------
class:       Log_BeforeImage
description: This defines the common part of all before images.
*/

class Log_BeforeImage : public Log_IImage
{

public:

    /*! --------------------------------------------------------------------------------
    function:     Log_BeforeImage
    */
    Log_BeforeImage (Log_ActionType ActionType = Log_NoOp)
    : m_pState(NULL),
      m_Head   ()
    {
        SetActionType (ActionType);
    }
    
    /*! --------------------------------------------------------------------------------
    function:     GetPersistentLength
    returns:      SAPDB_UInt
    descriptions: The persistent length is calculated and returned.
    */
    static SAPDB_UInt GetPersistentLength ()
    {
        return sizeof (Head);
    }

    /*  --------------------------------------------------------------------------------
    function:    IsAfterImage
    description: returns true, if image is an after image.
    ----------------------------------------------------------------------------------*/ 
    virtual bool IsAfterImage () const
    {
        return false;
    }

    /*! --------------------------------------------------------------------------------
    function:    WritePersistentFormat
    arguments:   Writer    [in]
                 isOK      [out]
    description: The Space must be initialized with the value given by GetPersistentLength().
    */
    virtual void WritePersistentFormat (Data_SplitSpaceWriter &Writer,
                                        bool                  &isOK) const
    {
        isOK = true;
        Data_SplitSpaceWriter::Result  result;
        Head                          *pHead;
        
        Writer.Reserve (sizeof(Head), REINTERPRET_CAST(SAPDB_Byte*&,pHead), result);
                        
        isOK = Data_SplitSpaceWriter::ok                 == result ||
               Data_SplitSpaceWriter::moreSpaceAvailable == result;
        if ( ! isOK ) return;

        *pHead = m_Head;
    }

    /*! --------------------------------------------------------------------------------
    function:    ReadPersistentFormat
    arguments:   Reader    [in/out]
                 isOK      [out]
                 checkAlignment [in]
    description: The Space must be initialized with the value given by GetPersistentLength().
    */
    virtual void ReadPersistentFormat (Data_SplitSpaceReader &Reader,
                                       bool                  &isOK,
                                       bool                   checkAlignment = false)
    {
        isOK = true;
        Data_SplitSpaceReader::Result  result;
        Head                          *pHead = 0;
        
        m_Head.Init(); // PTS 1114727 UH 2002-03-07
        
        Reader.Reserve (sizeof(Head), reinterpret_cast<SAPDB_Byte*&>(pHead), result, checkAlignment);
                        
        isOK = (Data_SplitSpaceReader::ok                 == result ||
                Data_SplitSpaceReader::moreSpaceAvailable == result)
               &&
               (0 != pHead); // PTS 1118382 UH 2002-10-17


        if ( ! isOK )
        {
            if ( LogHistory_Trace.TracesLevel(6) || Data_SplitSpaceReader::reservedSpaceNotAligned == result )
            {
                // PTS 1118382 UH 2002-10-17
                Kernel_VTrace() << "result: " << result << ((pHead==0)?", pHead is NULL":"");
                Reader.WriteToTrace("reader:");
            }
            return;
        }

        m_Head   = *pHead;
        m_pState = &(pHead->StatePersistent);
    }

    /*! --------------------------------------------------------------------------------
    function:    WriteToTrace
    arguments:   Title [in]
    description: writes the before image to the trace.
    */
    virtual void WriteToTrace (const char * Title = NULL) const
    {
        Kernel_VTrace trace;
        
        if ( Title != NULL )
            trace << Title << "\n";
        trace << "BeforeImage: (" << GetSequence() << ") '"
              << Log_GetActionTypeString(GetActionType())
              << "' state= "     << m_Head.StatePersistent
              << " ConsistView: " << m_Head.ConsistentView.gg90GetInt4() << NewLine;
        trace << "PrevUpdTrNo: " << m_Head.PreviousUpdateTransNo.gg90GetInt4()
              << ", PrevState: " << (int)GetPreviousState()
              << ", PrevImage: " << m_Head.PreviousImage.gg91RefPno()
              << "." << m_Head.PreviousImage.gg91RefPos() << NewLine;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetSequence
    arguments:   NewSequence [in]
    */
    void SetSequence (const Log_EntrySequence& NewSequence)
    {
        m_Head.Sequence = NewSequence;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetSequence
    returns:     The sequence.
    */
    virtual Log_EntrySequence GetSequence() const
    {
        return m_Head.Sequence;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetRollbacked
    arguments:   inPersistentFormat [in]
    description: Within the entry it is stored, that it is rollbacked by transaction.
    */
    void SetRollbacked (bool inPersistentFormat)
    {
        SetState (inPersistentFormat, rollbacked);
    }

    /*! --------------------------------------------------------------------------------
    function:    SetDeleted
    arguments:   inPersistentFormat [in]
    description: Within the entry it is stored, that it is deleted by garbage collector.
    */
    void SetDeleted (bool inPersistentFormat)
    {
        SetState (inPersistentFormat, deleted);
    }

    /*! --------------------------------------------------------------------------------
    function:    IsRollbacked
    arguments:   inPersistentFormat [in]
    returns:     true, if entry is already rollbacked.
    */
    bool IsRollbacked (bool inPersistentFormat) const
    {
        return GetState (inPersistentFormat) == rollbacked;
    }

    /*! --------------------------------------------------------------------------------
    function:    IsDeleted
    arguments:   inPersistentFormat [in]
    returns:     true, if entry is already deleted.
    */
    bool IsDeleted (bool inPersistentFormat) const
    {
        return GetState (inPersistentFormat) == deleted;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetActionType
    */
    void SetActionType (Log_ActionType NewType)
    {
        m_Head.ActionType = NewType;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetActionType
    */
    virtual Log_ActionType GetActionType() const
    {
        if ( m_Head.ActionType >= Log_ActionType_DO_NOT_USE )
            return Log_NoOp;
        else
            return STATIC_CAST(Log_ActionType, m_Head.ActionType);
    }

    /*! --------------------------------------------------------------------------------
    function:    SetLastRedoSequence
    */
    void SetLastRedoSequence (Log_EntrySequence LastRedoSequence)
    {
        m_Head.LastRedoSequence = LastRedoSequence;;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetLastRedoSequence;
    */
    Log_EntrySequence GetLastRedoSequence() const
    {
        return m_Head.LastRedoSequence;;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetConsistentView
    */
    void SetConsistentView (tgg91_TransNo& NewConsistentView)
    {
        m_Head.ConsistentView = NewConsistentView;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetConsistentView
    */
    const tgg91_TransNo& GetConsistentView() const 
    {
        return m_Head.ConsistentView;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetPreviousUpdateTransNo
    */
    void SetPreviousUpdateTransNo (tgg91_TransNo& PrevUpdTransNo)
    {
        m_Head.PreviousUpdateTransNo = PrevUpdTransNo;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetPreviousUpdateTransNo
    */
    const tgg91_TransNo& GetPreviousUpdateTransNo() const
    {
        return m_Head.PreviousUpdateTransNo;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetPreviousImage
    */
    void SetPreviousImage (Data_PageNo     pno,
                           Data_PageOffset offset)
    {
        m_Head.PreviousImage.gg91BuildRef(pno,offset);
    }

    /*! --------------------------------------------------------------------------------
    function:    GetPreviousImage
    */
    void GetPreviousImage (Data_PageNo     &pno,
                           Data_PageOffset &offset) const
    {
        pno    = m_Head.PreviousImage.gg91RefPno();
        offset = m_Head.PreviousImage.gg91RefPos();
    }

    /*! --------------------------------------------------------------------------------
    function:    GetPreviousImage
    */
    const tgg91_PageRef& GetPreviousImage () const
    {
        return m_Head.PreviousImage;
    }

    /*! --------------------------------------------------------------------------------
    function:    SetPreviousState
    */
    void SetPreviousState (tgg00_ObjState NewPrevState)
    {
        m_Head.PreviousState = NewPrevState;
    }

    /*! --------------------------------------------------------------------------------
    function:    GetPreviousState
    */
    const tgg00_ObjState& GetPreviousState() const
    {
        return m_Head.PreviousState;
    }

public:

    /*! --------------------------------------------------------------------------------
    declaration: State
    description: none, rollbacked, deleted
    */
    enum State
    {
        created    = 0,
        rollbacked = 1,
        deleted    = 2
    };

private:

    /*! --------------------------------------------------------------------------------
    function:    SetState
    */
    void SetState (bool  inPersistentFormat,
                   State state)
    {
        SAPDB_Byte* pDestination;
        
        if (inPersistentFormat)
            pDestination = m_pState;
        else
            pDestination = &(m_Head.StatePersistent);
            
        SAPDBERR_ASSERT_STATE(pDestination != NULL);
        
        switch (state)
        {
            case created:
                *pDestination = 0;
                break;
            case rollbacked:
                *pDestination = 1;
                break;
            case deleted:
                *pDestination = 2;
                break;
            default:
                RTE_Crash(SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,"unknown before image state"));
        }
    }

    /*! --------------------------------------------------------------------------------
    function:    GetState
    */
    State GetState (bool inPersistentFormat) const
    {
        if (inPersistentFormat)
        {
            SAPDBERR_ASSERT_STATE(m_pState != NULL);
            return State(*m_pState);
        }
        else
            return State(m_Head.StatePersistent);
    }

    /*! --------------------------------------------------------------------------------
    declaration: Head
    description: This header is used to identify the before image.

    ActionType    - The type of action, which is logged.
    SubTransNo    - The subtransaction layer.
    Sequence      - This entry sequence no is local to the transaction.
    */
    struct Head
    {
        SAPDB_Byte        ActionType;             // Log_ActionType 1 byte
        SAPDB_Byte        StatePersistent;        //                1 byte
        tgg00_ObjState    PreviousState;          //                1 byte
        SAPDB_Byte        Filler1;                //                1 byte
        Log_EntrySequence Sequence;               //                4 bytes
        Log_EntrySequence LastRedoSequence;       //                4 bytes
        tgg91_TransNo     ConsistentView;         //                6 bytes
        tgg91_TransNo     PreviousUpdateTransNo;  //                6 bytes
        tgg91_PageRef     PreviousImage;          //                6 bytes
        SAPDB_UInt2       Filler2;                //                2 byte
                                                  //               32 bytes        
        void Init()
        {
            ActionType        = Log_NoOp;
            StatePersistent   = 0;
            Sequence          = 0;
            LastRedoSequence  = 0;
            ConsistentView.gg90SetNil();
            PreviousUpdateTransNo.gg90SetNil();
            PreviousImage.gg91SetNilRef();
            PreviousState.becomes(obsFree_egg00);
            Filler1           = 0;
            Filler2           = 0;
        }

        Head()
        {
            Init();
        }
    };

    /*! --------------------------------------------------------------------------------
    variable:    m_Head
    */
    Head m_Head;

    /*! --------------------------------------------------------------------------------
    variable:    m_pState
    */
    SAPDB_Byte *m_pState;

};
/*! endclass: Log_BeforeImage */

/*===========================================================================*
*  DEFINITION OF INLINE METHODS                                              *
*============================================================================*/

#endif  /* Log_BeforeImage_H */
