#include "bb_helper.h"
#include "corba_obj_helper.h"
#include "entry.h"
#include "msg.h"
#include "opus_exceptions.h"

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::CORBA_entry_lock
//
// Purpose:
//
//    The constructor
//
// Description:
//
//    The constructor takes ownership of the input EntryLock object (which
//    is assumed to be in the locked state) and duplicates the Blackboard
//    object reference for internal use.
//
// Returns:
//
//    none
//
// Exceptions thrown:
//
//    Severe<void*> - if the CORBA Blackboard ID cannot be obtained;
//                    Severe.arg contains 0
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
// 10/29/02  46765    Sontag      Standardizing for the gcc 3.2 compiler
//
//////////////////////////////////////////////////////////////////////////

template<BB_Helper::TYPE T>
CORBA_entry_lock<T>::CORBA_entry_lock(
               OPUS::OPUS_API::BB::EntryLock* l,     // lock object
               OPUS::OPUS_API::BB::Blackboard_ptr b) // Blackboard ref.
                                                      : lock_obj(l),
                                                        bb(b)
{
   OPUS::OPUS_API::BB::BBStateInfo_var state;
   try {
      state = bb->getState();
   }
   catch(CORBA::SystemException&) {
      Msg m;
      m << sev(Msg::E) << type(Msg::SEVERE) <<
         "CORBA_entry_lock::CORBA_entry_lock - getState call on CORBA"
         " Blackboard failed." << endm;
      throw Severe<void*>(0);
   }
   bbid = std::string(state->id); // extract ID string for use in operator==
   locked = true;
}

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::~CORBA_entry_lock
//
// Purpose:
//
//    The destructor
//
// Description:
//
//    The lock on the entry is released if still locked.
//
// Returns:
//
//    none
//
// Exceptions thrown:
//
//    none
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
//
//////////////////////////////////////////////////////////////////////////

template <BB_Helper::TYPE T>
CORBA_entry_lock<T>::~CORBA_entry_lock()
{
   try {
      if (locked) bb->unlockEntry(lock_obj->id);
   }
   catch(...) {
      Msg m;
      m << sev(Msg::E) << type(Msg::LOCK) <<
         "CORBA_entry_lock::~CORBA_entry_lock - An exception was thrown"
         " while attempting to release the lock on the CORBA Blackboard."
         << endm;
   }
}

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::lock
//
// Purpose:
//
//    Locks the entry
//
// Description:
//
//    Calls lockEntry on the CORBA Blackboard if not already locked.
//
// Returns:
//
//    none
//
// Exceptions thrown:
//
//    Bad_val<string> - if the Entry to be locked is badly formatted;
//                      Bad_val arg contains a copy of the error message
//    Locked<string>  - if the CORBA Blackboard reports that the Entry 
//                      already is locked; Locked.arg contains a copy of
//                      the error message
//    Exec<string>    - if an unexpected OAPI exception is thrown;
//                      Exec.arg contains a copy of the error message
//    Severe<string>  - if a CORBA exception is thrown;
//                      Severe.arg contains a copy of the error message
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
//
//////////////////////////////////////////////////////////////////////////

template<BB_Helper::TYPE T>
void CORBA_entry_lock<T>::lock()
{
   if (locked) return;
   try {
      lock_obj = bb->lockEntry(lock_obj->lockedEntry);
      locked = true;
   }
   catch(const OPUS::OPUS_API::EXCEPTIONS::BadVal& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::BADVAL) <<
         "CORBA_entry_lock::lock - A BadVal exception was thrown: " << msg
         << endm;
      throw Bad_val<std::string>(msg, msg);
   }
   catch(const OPUS::OPUS_API::EXCEPTIONS::Locked& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::DUPL) <<
         "CORBA_entry_lock::lock - A Locked exception was thrown: " << msg
         << endm;
      throw Locked<std::string>(msg, msg);
   }
   catch(const OPUS::OPUS_API::EXCEPTIONS::Exec& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::EXEC) <<
         "CORBA_entry_lock::lock - An Exec exception was thrown: " << msg
         << endm;
      throw Exec<std::string>(msg, msg);
   }
   catch(const CORBA::Exception& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::FIO) <<
         "CORBA_entry_lock::lock - A CORBA exception was thrown: " << msg
         << endm;
      throw Severe<std::string>(msg, msg);
   }
}

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::release
//
// Purpose:
//
//    Release the lock on the entry
//
// Description:
//
//    Calls unlockEntry on the CORBA Blackboard if locked.
//
// Returns:
//
//    none
//
// Exceptions thrown:
//
//    Already<string> - if the CORBA Blackboard reports the object
//                      already unlocked; Already.arg contains a copy of
//                      the error message
//    Severe<string>  - if a CORBA exception is thrown;
//                      Severe.arg contains a copy of the error message
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
//
//////////////////////////////////////////////////////////////////////////

template<BB_Helper::TYPE T>
void CORBA_entry_lock<T>::release()
{
   if (!locked) return;
   try {
      bb->unlockEntry(lock_obj->id);
      locked = false;
   }
   catch(const OPUS::OPUS_API::EXCEPTIONS::Already& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::EXEC) <<
         "CORBA_entry_lock::release - An Already exception was thrown: " 
        << msg << endm;
      throw Already<std::string>(msg, msg);
   }
   catch(const CORBA::Exception& ex) {
      std::string msg(CORBA_obj_helper::get_exception_text(ex));
      Msg m;
      m << sev(Msg::E) << type(Msg::FIO) <<
         "CORBA_entry_lock::release - A CORBA exception was thrown: " << msg
         << endm;
      throw Severe<std::string>(msg, msg);
   }

}

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::operator==
//
// Purpose:
//
//    Test for CORBA_entry_lock equality
//
// Description:
//
//    Tests the supplied lock object for equality (a lock object for the
//    same Entry). Two objects of this type are equal if they are both
//    of type CORBA_entry_lock, refer to the same Blackboard ID, and their
//    Entry unique ID's are the same.
//
// Returns:
//
//    true if equal; false otherwise
//
// Exceptions thrown:
//
//    EFROM->BB_Helper::create_oapi_entry
//    EFROM->BB_Helper::generate_id
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
//
//////////////////////////////////////////////////////////////////////////

template<BB_Helper::TYPE T>
bool CORBA_entry_lock<T>::operator==(const Opus_lock* l) const
{
   const CORBA_entry_lock<T>* ll = dynamic_cast<const CORBA_entry_lock<T>*>(l);
   if (!ll) return false;

   if (bbid != ll->bbid) return false;

   Entry* this_target = 0;
   Entry* that_target = 0;
   try {
      this_target = BB_Helper::create_oapi_entry(T, lock_obj->lockedEntry);
      that_target = BB_Helper::create_oapi_entry(T, ll->lock_obj->lockedEntry);
   }
   catch(...) {
      delete this_target;
      delete that_target;
      throw;
   }
   if (BB_Helper::generate_id(T, this_target) != 
       BB_Helper::generate_id(T, that_target)) {
      delete this_target;
      delete that_target;
      return false;
   } else {
      delete this_target;
      delete that_target;
      return true;
   }
}

//////////////////////////////////////////////////////////////////////////
//
// Method: CORBA_entry_lock<T>::get_locked_entry
//
// Purpose:
//
//    Obtain a copy of the locked Entry.
//
// Description:
//
//    Instantiates a copy of the locked Entry off the heap.
//
// Returns:
//
//    A pointer to a copy of the locked Entry; the caller should delete
//    the returned object when it is no longer needed.
//
// Exceptions thrown:
//
//    Not_ready<void*> - if the Entry is not locked;
//                       Not_ready.arg contains 0
//    EFROM->BB_Helper::create_oapi_entry
//
// Example:
//
//    none
//
// Modification History:
//
// Date      OPR      Who         Reason
// --------- -------- ----------- ----------------------------------------
// 02/04/02  44741    WMiller     Initial code
//
//////////////////////////////////////////////////////////////////////////

template<BB_Helper::TYPE T>
Entry* CORBA_entry_lock<T>::get_locked_entry() const
{
   if (!locked) {
      Msg m;
      m << sev(Msg::E) << type(Msg::MISUSE) <<
        "CORBA_entry_lock::get_locked_entry - Target not locked." << endm;
      throw Not_ready<void*>(0);
   }
   return BB_Helper::create_oapi_entry(T, lock_obj->lockedEntry);
}
