/*!
  @file           SAPDBFields_Field.hpp
  @author         StefanB, UweH
  @ingroup        Field
  @brief          class declarations for Field

\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 SAPDBFIELDS_FIELD_HPP
#define SAPDBFIELDS_FIELD_HPP

#include <string.h> // memmove
#include "SAPDBCommon/SAPDB_Types.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"


/*!
@class SAPDBFields_Field
@brief A handler to a contiguous memory block of certain size.

The memory block is fixed in content and size, that means 
SAPDBFields_Field has only methods for reading the content and no 
methods for changing the content.
*/
class SAPDBFields_Field
{
public:
	/// The range for field lengths
    typedef SAPDB_UInt                  SizeType;
	///The range for positions within fields
	typedef SizeType                    IndexType;
    /// Pointer to field data
	typedef SAPDB_Byte*                 Pointer;
	/// Pointer to constant field data
    typedef const Pointer               ConstPointer;
	/// Field iterator referencing constant data
    typedef ConstPointer                ConstIterator;

private:
	/// Pointer to memory block
	Pointer   m_DataPtr;
	/// Count of elements of SAPDB_Byte in memory block
    SizeType  m_DataLen;

public:
	/// Constructs an empty field
	SAPDBFields_Field()
    : m_DataPtr(0),
      m_DataLen(0)
	{}
    /*!
    @brief          Constructs a field pointing to Src with length Len.
    @param          Src [in] The address of the memory block
    @param          Len [in] The length of the memory block in sizeof(SAPDB_Byte)
    */
    SAPDBFields_Field(void * Src, SizeType Len) 
      : m_DataPtr(reinterpret_cast<Pointer>(Src)), m_DataLen(Len) {}
    /*!
    @brief Assigns values for the memory block pointer and length
    @param          Src [in] Pointer to memory block
    @param          Len [in] Length of memory block
    */
    void Assign(void *Src, SizeType Len)
    {
        m_DataPtr = reinterpret_cast<Pointer>(Src);
        m_DataLen = Len;
    }
    /*!
    @brief Assigns values for the memory block pointer.
    @param          Field [in] Another field
    */
    void Assign(const SAPDBFields_Field& Field)
    {
        m_DataPtr = Field.m_DataPtr;
        m_DataLen = Field.m_DataLen;
    }
	/// Deassigns a Field
    void Deassign()
    {
        m_DataPtr = 0;
        m_DataLen = 0;
	}
	/*!
    @brief  Assigns an empty field.
    
    The field is simply assigned to the this-pointer with length zero.
    */
    void AssignEmpty() 
    {
        Assign(this, 0);
	}
    /*!
    @brief   Indicates, if the instance is already assigned to a memory block.
    @return  true if data ptr is assigned
    */
    bool IsAssigned() const
    {
        return m_DataPtr != 0;
	}
	/// Indicates, if the instance points to a (valid) memory block with a length of zero.
    bool IsEmpty() const
    { 
        return m_DataLen == 0;
    }
	/// Returns the length of the memory block in sizeof(SAPDB_Byte)
    SizeType GetLength() const
    {
        return m_DataLen;
    }
    /// returns true if given field is bytewise equal to current field.
    bool IsEqualTo(const SAPDBFields_Field& Field) const
    {
         if ( ! IsAssigned() )
             RTE_Crash(SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "current field.m_DataPtr not nil"));
         if ( ! Field.IsAssigned() )
             RTE_Crash(SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "given field.m_DataPtr not nil"));
        return m_DataLen == Field.m_DataLen
               && 
               ! memcmp(m_DataPtr, Field.m_DataPtr, GetLength());
    }
    /// returns true if current field is smaller then given field.
    bool IsSmallerThan(const SAPDBFields_Field& Field) const
    {
         const SizeType Len = (Field.m_DataLen < m_DataLen) ? Field.m_DataLen : m_DataLen;
         if ( ! IsAssigned() )
             RTE_Crash(SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "current field.m_DataPtr not nil"));
         if ( ! Field.IsAssigned() )
             RTE_Crash(SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "given field.m_DataPtr not nil"));
         const int result = memcmp(m_DataPtr, Field.m_DataPtr, Len * sizeof(SAPDB_Byte));
         return ( (result < 0) || ( (result == 0) && (m_DataLen < Field.m_DataLen) ) );
    }
    /*!
    @brief   Checks, if two fields point to the same memory block
    @param   Field [in] The instance for the comparison
    @return  bool
    */
	bool operator ==(const SAPDBFields_Field& Field) const
    {
        return m_DataPtr == Field.m_DataPtr
               &&
               m_DataLen == Field.m_DataLen;
    }
    /*!
    @brief          Checks the opposite of ==
    @param          Field [in] The instance for the comparison
    @return         bool
    */
    bool operator !=(const SAPDBFields_Field& Field) const
    {
        return ! (*this == Field);
    }
	/// Returns an iterator which points to the begin of the memory block
    ConstIterator Begin() const
    {
        return m_DataPtr;
    }
	/// Returns an iterator which points behind the end of the memory block.
    ConstIterator End() const
    {
        return m_DataPtr + m_DataLen;
    }
	/// Returns the address of the constant memory block
    ConstPointer GetDataPtr() const
    {
        return m_DataPtr;
    }
	/// Returns the address of the memory block
    Pointer GetDataPtr()
    {
        return m_DataPtr;
    }
    /*!
    @brief Returns the address of a certain position within the memory block
    @param          offset [in] The position within the memory block
    @param          length [in] The length which is required (optional)
    @return         ConstPointer

	The field must be not empty.
    */
    ConstPointer GetPointer( IndexType offset,
                             SizeType  length = 0) const
    {
        SAPDBERR_ASSERT_ARGUMENT(offset < m_DataLen);
        SAPDBERR_ASSERT_ARGUMENT(offset+length-1 < m_DataLen);
        return m_DataPtr + offset;
    }
    /*!
    @brief Returns the address of a certain position within the memory block
    @param          offset [in] The position within the memory block
    @param          length [in] The length which is required (optional)
    @return         Pointer

	The field must be not empty.
    */
    Pointer GetPointer( IndexType offset,
                        SizeType  length = 0)
    {
        SAPDBERR_ASSERT_ARGUMENT(offset < m_DataLen);
        SAPDBERR_ASSERT_ARGUMENT(offset+length-1 < m_DataLen);
        return m_DataPtr + offset;
    }
    /*!
    @brief Returns the the byte from the given offset position.
    @param          offset [in] The position within the memory block
    @return         the byte

	The field must be not empty.
    */
    SAPDB_Byte GetByteAt ( IndexType offset ) const
    {
        return *(GetPointer(offset,sizeof(SAPDB_Byte)));
    }
    /*!
    @brief Copies the contents from given field to current field.
    @return false if current field length is too small or one of the fields is not assigned
    
    If the given Field points to the same memory nothing is done and true returned.
    */
    bool Copy (const SAPDBFields_Field& Field)
    {
        if ( *this == Field )
            return true;
            
        if ( GetLength() < Field.GetLength()
             ||
             ! IsAssigned() || ! Field.IsAssigned() )
            return false;
            
        m_DataLen = Field.m_DataLen;
        memcpy ( m_DataPtr, Field.GetDataPtr(), m_DataLen);
        
        return true;
    }
};
#endif // SAPDBFIELDS_FIELD_HPP

