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

  module      : RTE_Global.cpp

  -------------------------------------------------------------------------

  responsible : JoergM

  special area: RTE Global Singleton
  description : Class definining all global RTE interfaces


  last changed: 2000-07-26  15:00
  see also    : example.html ...

  -------------------------------------------------------------------------





    ========== 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




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



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

#include "SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp" // required for placement new
#include "RunTime/RTE_IGlobal.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "RunTime/Tasking/RTETask_IContext.hpp"
#include "RunTime/Threading/RTEThread_IContext.hpp"
#include "RunTime/RTE_MessageList.hpp"

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

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

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

/*!
  class:       RTE_Global
  description: TheRTE Singleton class
  
  This class contains all functions provided to all threads or tasks inside a process.
  
  Instead of TheRTE 'RTE_IGlobal::Instance() could be used, but this seemed to long...
 */
class RTE_Global : public RTE_IGlobal
{
public:
  /*!
    function: CurrentTaskContext
    description: Get current task context pointer

    If this function is called within a task, the pointer to the task context is returned.

    return value: Current Task Pointer or NULL if not called within a task
   */
  RTETask_IContext   * CurrentTaskContext();

  /*!
    function: CurrentThreadContext
    description: Get current thread context pointer

    If this function is called within a thread, the pointer to the thread context is returned.
    
    return value: Current Thread Pointer or NULL if not called within multithreading RTE
   */
  RTEThread_IContext * CurrentThreadContext();

  /*!
    function: MapTaskContext
    description: Get current thread context pointer

    If this function is called with a valid TaskId, the pointer to the correspnding task context
    is returned.

    arguments: TaskId [in] The unique TaskId to map

    return value: Task Context pointer containing the TaskId or NULL if no matching TaskId found
   */
  RTETask_IContext   * MapTaskContext(RTE_TaskId TaskId);

  /*!
    Function: GetLastErrorMessage
    Description: Get copy of last error message list

    The internal stored message list is only meaningfull, if retrieved after an error
    was reported. You will always retrieve the complete last error message list, including all
    appended messages.
    
    Return value: Last Error Message list set by any error reporting call via SetLastErrorMessage()
   */
  virtual const SAPDBErr_MessageList & GetLastErrorMessage();

  /*!
    Function: SetLastErrorMessage
    Description: Get copy of last error message list

    The internal stored message list is only meaningfull, if retrieved after an error
    was reported. You will always retrieve the last error occured!

    Arguments: LastErrorMessage [in] Message to set or append
               DoAppend [in] Flag to indicate replacement or appending of LastErrorMessage
   */
  virtual void SetLastErrorMessage(const SAPDBErr_MessageList & LastErrorMessage, SAPDB_Bool DoAppend);

private:
  RTE_Global();        // This class is a singleton

  RTE_TLSKey           m_ThreadKey;   // The Key storing the TLS Key to find current thread
  RTEThread_IContext **m_ThreadArray; // Pointer to the thread context pointer array
  RTETask_IContext   **m_TaskArray;   // Pointer to the task context pointer array
  RTE_TaskId           m_MaxTaskId;   // Maximum allowed Task Id
  static RTE_IGlobal  *m_Instance;    // Pointer to the RTE_Global instance
  SAPDBErr_MessageList m_LastErrorMessage; // Last error message if no threads used
  friend class RTE_IGlobal;
}; /* endclass: RTE_Global */

RTE_IGlobal * RTE_Global::m_Instance = (RTE_IGlobal *)0;

/*===========================================================================*
 *  STATIC/INLINE FUNCTIONS (PROTOTYPES)                                     *
 *===========================================================================*/

/*===========================================================================*
 *  METHODS                                                                  *
 *===========================================================================*/
//---------------------------------------------------------------------------
RTE_Global::RTE_Global()
: m_ThreadKey(0), m_ThreadArray(0), m_TaskArray(0), m_MaxTaskId(0), 
  m_LastErrorMessage(RTE_CONTEXT, SAPDBErr_MessageList::Info, 0, "", 0)
{
}
//---------------------------------------------------------------------------
RTETask_IContext * RTE_Global::CurrentTaskContext()
{
  RTEThread_IContext * Thread = CurrentThreadContext();

  return ( Thread ? Thread->CurrentTaskContext() : (RTETask_IContext *)0 );
}
//---------------------------------------------------------------------------
RTEThread_IContext * RTE_Global::CurrentThreadContext()
{
  // ask thread local storage...
  return reinterpret_cast<RTEThread_IContext *>(
                          RTEThread_IContext::GetTLS(m_ThreadKey));
}
//---------------------------------------------------------------------------
RTETask_IContext * RTE_Global::MapTaskContext(RTE_TaskId TaskId)
{
  SAPDBERR_ASSERT_ARGUMENT(m_TaskArray);
  SAPDBERR_ASSERT_ARGUMENT(TaskId > 0);
  SAPDBERR_ASSERT_ARGUMENT(m_MaxTaskId > 0 && TaskId <= m_MaxTaskId);

  return m_TaskArray[TaskId];
}
//---------------------------------------------------------------------------
// Find the right context for the message and then get it
const SAPDBErr_MessageList & RTE_Global::GetLastErrorMessage()
{
  RTEThread_IContext * Thread = CurrentThreadContext();

  if ( !Thread )
  {
    return m_LastErrorMessage;
  }

  RTETask_IContext * Task = Thread->CurrentTaskContext();

  if ( !Task )
  {
    return Thread->GetLastErrorMessage();
  }
  else
  {
    return Task->GetLastErrorMessage();
  }
}
//---------------------------------------------------------------------------
// Find the right context for the message and then set it
void RTE_Global::SetLastErrorMessage(const SAPDBErr_MessageList & LastErrorMessage, SAPDB_Bool DoAppend)
{
  RTEThread_IContext * Thread = CurrentThreadContext();

  if ( !Thread )
  {
    if ( DoAppend )
    {
      m_LastErrorMessage.AppendNewMessage(LastErrorMessage);
    }
    else
    {
      m_LastErrorMessage = LastErrorMessage;
    }
  }

  RTETask_IContext * Task = Thread->CurrentTaskContext();

  if ( !Task )
  {
    Thread->SetLastErrorMessage(LastErrorMessage, DoAppend);
  }
  else
  {
    Task->SetLastErrorMessage(LastErrorMessage, DoAppend);
  }
}
//---------------------------------------------------------------------------
//
// This static member function is defined in RTE_IGlobal class and implemented here
// since it needs size of RTE_Global class which is not visible to the interface.
//
RTE_IGlobal & RTE_IGlobal::Instance()
{
  RTE_IGlobal::Initialize();

  SAPDBERR_ASSERT_STATE(RTE_Global::m_Instance);

  return *RTE_Global::m_Instance;
}
//---------------------------------------------------------------------------
//
// This static member function is defined in RTE_IGlobal class and implemented here
// since it needs size of RTE_Global class which is not visible to the interface.
//
void RTE_IGlobal::Initialize( )
{
  SAPDBMEM_STATIC_RAW_ALLOCATE(Space, sizeof(RTE_Global));
  
  if ( !RTE_Global::m_Instance )
  {
    RTE_Global::m_Instance = new (Space) RTE_Global();
  }
}

/*===========================================================================*
 *  END OF CODE                                                              *
 *===========================================================================*/
