// ==================================================
// Copyright 2014.
// Siemens Product Lifecycle Management Software Inc.
// All Rights Reserved.
// ==================================================

/**
    @file

    This file contains the declaration for a BusinessObjectExtenderRef smart pointer.
*/

/*  */

#ifndef TCBUSINESSOBJECTEXTENDERREF_HXX
#define TCBUSINESSOBJECTEXTENDERREF_HXX

#include <unidefs.h>
#include <metaframework/BusinessObjectExtenderRegistry.hxx>
#include <metaframework/RootObject.hxx>

/**
    @ingroup BO
    @{

    @brief BusinessObjectExtenderRef smart pointer.

    BusinessObjectExtenderRef smart pointer. It is similar BusinessObjectRef.

    @code
    tag_t owningObjectTag = fromSomewhere();
    ...
    BusinessObjectExtenderRef<ExtenderObjectQualifiedName> extenderRef( owningObjectTag );
    extenderRef->getXYZ(...);
    @endcode
*/
template <typename T> class BusinessObjectExtenderRef
{
public:

    /**
        Default constructor
    */
    BusinessObjectExtenderRef(): m_owning_obj_tag(0), m_pointee( 0 ) {}

    /**
        Constructor
    */
    explicit BusinessObjectExtenderRef(
        tag_t owning_obj_tag               /**< (I) The input Owning Object tag */
        )
        : m_owning_obj_tag( owning_obj_tag ), m_pointee( 0 )
    {}

    /**
        Constructor
    */
    explicit BusinessObjectExtenderRef(
        Teamcenter::RootObject owning_object               /**< (I) The input Owning Object */
        )
        : m_owning_obj_tag( 0 ), m_pointee( 0 )
    {
        m_owning_obj_tag = owning_object.getTag();
        m_pointee = getPointee();
    }

    /**
        Template for BusinessObjectExtenderRef
    */
    template<typename S> explicit  BusinessObjectExtenderRef(const BusinessObjectExtenderRef<S> &other)
    {
        m_owning_obj_tag = other.m_owning_obj_tag;
        m_pointee = other.m_pointee ? dynamic_cast<T*>(other.m_pointee) : 0;
    }

    /**
        Copy constructor for BusinessObjectExtenderRef
    */
    BusinessObjectExtenderRef& operator = (
        const BusinessObjectExtenderRef& other               /**< (I) The input BusinessObjectExtenderRef */
        )
    {

        if ( this != &other )
        {
            m_pointee = other.m_pointee;
            m_owning_obj_tag = other.m_owning_obj_tag;
        }
        return *this;
    }

    /**
        Assignment operator for BusinessObjectExtenderRef
    */
    BusinessObjectExtenderRef& operator = (
        tag_t owning_obj_tag               /**< (I) The input Owning Object tag */
        )
    {
        m_pointee = 0;
        m_owning_obj_tag = owning_obj_tag;
        return *this;
    }

    /**
        Operator to return a pointer to the BusinessObjectExtenderRef
    */
    T* operator->() const { return getPointee(); }

    /**
        Operator to return a reference to the BusinessObjectExtenderRef
    */
    const T& operator*() const { return *getPointee(); }

    /**
        Template for isInstanceOf

        @returns true if input class is an instance of this class.
    */
    template <typename U> bool isInstanceOf() const
    {
        return dynamic_cast<U*>(getPointee()) ? true : false;
    }

    /**
        Destructor for a BusinessObjectExtenderRef
    */
    virtual ~BusinessObjectExtenderRef()
    {
        m_pointee = 0;
    }

private:

    T* getPointee() const
    {
        if ( m_owning_obj_tag && !m_pointee )
        {
            m_pointee = T::extenderRegistry().findExtenderObject( m_owning_obj_tag );
        }
        return m_pointee;
    }

    template<typename S> friend class BusinessObjectExtenderRef;

    /**
        The Owning object tag
    */
    tag_t m_owning_obj_tag;

    mutable T* m_pointee;
};

/** @} */

#endif
