#include "Teuchos_oblackholestream.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
#include "Teuchos_Assert.hpp"
#include "Teuchos_getConst.hpp"
#include "Teuchos_Version.hpp"
#ifdef HAVE_TEUCHOS_BOOST
#  include "Teuchos_RCPBoostSharedPtrConversions.hpp"
#endif
#include "TestClasses.hpp"
#define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
#define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
int main( int argc, char* argv[] ) {
  using Teuchos::deallocFunctorDelete;
  using Teuchos::deallocFunctorHandleDelete;
  using Teuchos::null;
  using Teuchos::rcpFromRef;
  using Teuchos::inOutArg;
  using Teuchos::rcp_implicit_cast;
  using Teuchos::rcp_const_cast;
  using Teuchos::rcp_static_cast;
  using Teuchos::rcp_dynamic_cast;
  using Teuchos::set_extra_data;
  using Teuchos::get_extra_data;
  using Teuchos::get_nonconst_extra_data;
  using Teuchos::get_optional_extra_data;
  using Teuchos::get_optional_nonconst_extra_data;
  using Teuchos::get_dealloc;
  using Teuchos::get_nonconst_dealloc;
  using Teuchos::get_optional_dealloc;
  using Teuchos::get_optional_nonconst_dealloc;
  using Teuchos::rcpWithEmbeddedObj;
  using Teuchos::rcpWithEmbeddedObjPreDestroy;
  using Teuchos::rcpWithEmbeddedObjPostDestroy;
  using Teuchos::getEmbeddedObj;
  using Teuchos::getNonconstEmbeddedObj;
  bool success = true;
  bool createCircRefs = false; 
  std::ostream &out = ( procRank == 0 ? std::cout : blackhole );
  try {
    
    CommandLineProcessor clp(false); 
    clp.setOption( "create-circ-refs", "no-create-circ-refs", &createCircRefs,
      "Set if output is printed or not." );
    CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
    if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
      out << "\nEnd Result: TEST FAILED" << std::endl;
      return parse_return;
    }
    blackhole << "\nThis should not print anywhere.\n";
    out << std::endl << Teuchos::Teuchos_Version() << std::endl;
    out << "\nTesting basic RCP functionality ...\n";
    
    RCP<A> a_ptr1 = 
rcp(
new C);
 
    out << "\na_ptr1 = " << a_ptr1 << "\n";
    
    
    
    
    
    
    
    
    
    
    RCP<D> d_ptr1 = 
rcp(
new E);
 
    {
      
#ifdef SHOW_RUN_TIME_ERROR_1
      
      
      const RCP<A> a_ptr2 = a_ptr1.get();
#endif
      
#ifdef SHOW_COMPILE_TIME_ERRORS
      ca_ptr1 = ca_ptr1; 
      ca_ptr1->A_g(); 
#endif
      
      
      
      
      
      
      
      
      
      
      const RCP<C>
      
      const RCP<const E>
      
      
#ifdef SHOW_COMPILE_TIME_ERRORS
      
#endif
#ifndef _INTEL // Intel compiler does not seem to be doing dynamic cast correctly?
#ifdef TEUCHOS_DEBUG // operator->() only throws std::exception when TEUCHOS_DEBUG is defined
      try {
        
        
        
        
        
        return -1; 
      }
      catch( const std::logic_error &excpt )
      {}
#endif
      try {
        
        
        
        
        return -1; 
      }
      catch( const std::bad_cast &excpt )
      {}
#endif
      
      delete d_ptr1.release().get(); 
      
#ifdef SHOW_RUN_TIME_ERROR_2
#endif
#ifdef SHOW_MEMORY_LEAK_1
      a_ptr1.release(); 
#endif
      
    }
    
    
    
    
    
    
    
    C c; 
#ifndef SHOW_RUN_TIME_ERROR_3
    
    a_ptr1.release();
#endif
    E e; 
#ifndef SHOW_RUN_TIME_ERROR_4
    
    d_ptr1.release();
#endif
#ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
    
    
    C *c_ptr5 = new C; 
#ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
    const void *c_ptr5_base = dynamic_cast<void*>(c_ptr5);
    out << "\nSize of C = " << sizeof(C) << std::endl;
    out << "Base address of object of type C = " << dynamic_cast<void*>(c_ptr5) << std::endl;
    out << "Offset to address of object of type C = " << ((long int)c_ptr5 - (long int)c_ptr5_base) << std::endl;
    out << "Offset of B1 object in object of type C = " << ((long int)static_cast<B1*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
    out << "Offset of B2 object in object of type C = " << ((long int)static_cast<B2*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
    out << "Offset of A object in object of type C = " << ((long int)static_cast<A*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
#endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
    A *a_rptr5 = c_ptr5; 
    a_ptr1 = null; 
#endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
    
    get_dealloc<DeallocDelete<C> >(a_ptr1);
    get_nonconst_dealloc<DeallocDelete<C> >(a_ptr1);
    
    
    
    {
      const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
      getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
      const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
    }
    {
      const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
      getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
      const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
    }
    {
      const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
      getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
      const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
    }
    
    int a_f_return = -2;
      "a_f_return", 
inOutArg(a_ptr1), Teuchos::PRE_DESTROY );
 
    
    a_ptr1 = null;
    d_ptr1 = null;
    
    
    
    
    a_ptr1 = null;
    
    a_ptr1 = 
rcpWithDealloc( 
new C, deallocFunctorHandleDelete<A>(deallocHandleA) );
 
    a_ptr1 = null;
#ifdef TEUCHOS_DEBUG
    if (createCircRefs) {
      out << "\nCreate a circular reference that will cause a memory leak! ...\n";
#  if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
      
      Teuchos::RCPNodeTracer::setTracingActiveRCPNodes(true);
#  endif
      RCP<C> c2 = 
rcp(
new C());
 
      a->set_C(c2);
      c2->set_A(a);
    }
#endif // TEUCHOS_DEBUG
#ifndef TEUCHOS_DEBUG
    out << "\nTesting using RCP to wrap an undefined opaque object (no TNT) ...\n";
    {
      RCP<UndefinedType> op_ptr =
                             deallocFunctorHandleDelete<UndefinedType> (destroyOpaque),
                             true);
    }
    
    
    
    
    
#endif // not TEUCHOS_DEBUG
    out << "\nTesting using RCP to wrap an undefined opaque object (with TNT) ...\n";
    {
        deallocFunctorHandleDelete<UndefinedType2>(destroyOpaque2) );
    }
    
    
    
#ifdef HAVE_TEUCHOS_BOOST
    out << "\nTesting basic RCP compatibility with boost::shared_ptr ...\n";
    boost::shared_ptr<A> a_sptr1(new C());
    RCP<A> a_rsptr1 = 
rcp(a_sptr1);
 
    
    
    RCP<A> a_rsptr2 = 
rcp(a_sptr2);
 
    
    out << "\nCompatibility with boost::shared_ptr passed ...\n";
#endif // HAVE_TEUCHOS_BOOST
    out << "\nAll tests for RCP seem to check out!\n";
  } 
  try {
    
    
    if (createCircRefs) {
      out << "\nPrinting the active nodes just to see them!\n";
#if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
#endif
    }
  } 
  if(success)
    out << "\nEnd Result: TEST PASSED" << std::endl;
  return ( success ? 0 : 1 );
}