/*!
  @file           Log_AfterImage.hpp
  @ingroup        Logging
  @author         UweH
  @brief          defines class Log_AfterImage, Log_AfterImageSpace

\if EMIT_LICENCE
    ========== 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

\endif
*/



#ifndef Log_AfterImage_H
#define Log_AfterImage_H

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

#include "SAPDBCommon/SAPDB_Types.hpp"
#include "KernelCommon/Kernel_VTrace.hpp"
#include "Logging/Log_Types.hpp"
#include "DataAccess/Data_ISplitSpace.hpp"
#include "Logging/Log_AfterImageSpace.hpp"
#include "Logging/Log_IImage.hpp"

#include "ggg91.h"

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

/// this entry had been already redone 
#define LOG_AFTER_IMAGE_IS_NOT_DONE SAPDB_FALSE

/// this entry had not been redone 
#define LOG_AFTER_IMAGE_IS_DONE     SAPDB_TRUE

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/
/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/
/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

/*!
    @class          Log_AfterImage
    @brief          This defines the common part of all after images.
                    It is in a persistent format.
 */
 

class Log_AfterImage : public Log_IImage
{
public:

    /// default constructor
    Log_AfterImage (Log_ActionType ActionType = Log_NoOp)
    : m_pIsDone (NULL) // PTS 1115068 UH 2002-03-27
    {
        m_Head.ActionType = ActionType;
		// PTS 1115068 UH 2002-03-27 initialization is done in ctor of m_Head
    }

    /// The persistent length is calculated and returned.
    static SAPDB_UInt GetPersistentLength ()
    {
        return sizeof(Head);
    }

    virtual bool IsAfterImage () const
    {
        return true;
    }

    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;
    }

    virtual void ReadPersistentFormat (Data_SplitSpaceReader &Reader,
                                       bool                  &isOK, // PTS 1115068 UH 2002-03-27 & was missing
                                       bool                   checkAlignment = false)
    {
        isOK = true;
        Data_SplitSpaceReader::Result  result;
        Head                          *pHead;

        m_Head.Init(); // PTS 1115068 UH 2002-03-27
        
        Reader.Reserve (sizeof(Head), REINTERPRET_CAST(SAPDB_Byte*&,pHead), result, checkAlignment);
                        
        isOK = Data_SplitSpaceReader::ok                 == result ||
               Data_SplitSpaceReader::moreSpaceAvailable == result;
        if ( ! isOK ) return;

        m_Head    = *pHead;
        m_pIsDone = &(pHead->IsDone); // PTS 1115068 UH 2002-03-27

    }

    /// sets the actiontype
    void SetActionType (Log_ActionType ActionType)
    {
        m_Head.ActionType = STATIC_CAST(SAPDB_Byte, ActionType);
    }

    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);
    }

    /// sets the transaction
    void SetTransNo (const tgg91_TransNo& TransNo)
    {
        m_Head.TransNo = TransNo;
    }
    
    /// returns the transaction-number
    const tgg91_TransNo& GetTransNo() const
    {
        return m_Head.TransNo;
    }

    /// set the UndoSequence for this action
    void SetLastUndoSequence (Log_EntrySequence LastUndoSequence)
    {
        m_Head.LastUndoSequence = LastUndoSequence;
    }

    /// get the UndoSequence for this action
    const Log_EntrySequence GetLastUndoSequence() const
    {
        return m_Head.LastUndoSequence;
    }

    /// sets the redo-sequence
    void SetSequence (Log_EntrySequence Sequence)
    {
        m_Head.Sequence = Sequence;
    }

    /// returns the redo-sequence
    virtual Log_EntrySequence GetSequence() const
    {
        return m_Head.Sequence;
    }

    /// Within the entry it is stored, that it is re done.
    void SetIsDone ()
    {
		// PTS 1115068 UH 2002-03-27
        SAPDB_Byte *pIsDone = m_pIsDone == NULL ? &m_Head.IsDone : m_pIsDone;
        *pIsDone = LOG_AFTER_IMAGE_IS_DONE;
    }

    /// true, if entry is already re done.
    bool IsDone () const
    {
		// PTS 1115068 UH 2002-03-27
        const SAPDB_Byte *pIsDone = m_pIsDone == NULL ? &m_Head.IsDone : m_pIsDone;
        return LOG_AFTER_IMAGE_IS_DONE == *pIsDone;
    }

    /// returns size of internal header
    static SAPDB_UInt GetHeaderSize()
    {
        return sizeof(Head);
    }
    
    virtual void WriteToTrace (const char *title = NULL) const
    {
        if ( title != NULL )
            Kernel_VTrace() << title;
        Kernel_VTrace() << "ActionType: " << Log_GetActionTypeString(GetActionType())
                        << ", IsDone: "   << (IsDone()?"yes":"no")
                        << ", Sequence: " << GetSequence()
                        << ", Transno: "  << GetTransNo().gg90GetInt4();
    }

private:

    /*!


       ActionType    - The type of action, which is logged.
       Sequence      - This entry sequence no is local to the transaction.
       TransNo       - The id of the transaction.
       SubTransNo    - The subtransaction layer.

     */

    /// This is the structured header for the after-image
    struct Head
    {
        /// The type of action, which is logged. (1 byte)
        SAPDB_Byte        ActionType;          

        /// if true: The action had been re-done (1 byte)
        SAPDB_Bool1       IsDone;              

        /// filler (2 byte)
        SAPDB_UInt2       Filler1;             

        /// This entry sequence no is local to the transaction. (4 bytes)
        Log_EntrySequence Sequence;            

        /// the sequencenumber of this entry for rollback (4 bytes)
        Log_EntrySequence LastUndoSequence;    

        /// The id of the transaction. (6 bytes)
        tgg91_TransNo     TransNo;             

        /// The subtransaction layer. (2 byte)
        SAPDB_UInt2       Filler2;             

        /// initializer
        void Init()
        {
			// PTS 1115068 UH 2002-03-27 new
            ActionType        = Log_NoOp;
            IsDone            = LOG_AFTER_IMAGE_IS_NOT_DONE;
            Sequence          = 0;
            LastUndoSequence  = 0;
            TransNo.gg90SetNil();
            Filler1           = 0;
            Filler2           = 0;
        }

        /// constructor
        Head()
        {
			// PTS 1115068 UH 2002-03-27 new
            Init();
        }

    };

    /// the in memory representation of the head
    Head m_Head;

    /*! @brief      flag, which denotes, if the AfterImage had been redone.
     *
     *  In the case of a rollback of a rollback, an entrie must not been
     *  rollbacked twice. In order to ensure this, the isDone-flag is checked
     *  before the entry is redone and set afterwards. Because the flag
     *  must be set not only in memory, but on the real page, this pointer
     *  may point to the isDone-Flag in the underlying page. */
    SAPDB_Byte *m_pIsDone;
};


/*===========================================================================*
*  DEFINITION OF INLINE METHODS                                              *
*============================================================================*/
                                       
#endif  /* Log_AfterImage_H */
