#include "Teuchos_ArrayRCP.hpp"
#include "Teuchos_VerboseObject.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
#include "Teuchos_Version.hpp"
#include "Teuchos_Assert.hpp"
template<class T>
bool test_ArrayRCP_iterators(
  )
{
  using Teuchos::null;
  using Teuchos::arcp;
  bool success = true;
  out
    << "\n***"
    << "\n*** Testing iterators and accessors for ptr = " << ptr
    << "\n***\n";
  const int size = ptr.size();
 
  
  {
    out << "\nChecking ++itr and < ...\n";
    for( 
int i = 0; itr < ptr+
size; ++i, ++itr )
 
  }
  {
    out << "\nChecking itr++ and <= ...\n";
    for( int i = 0; itr <= ptr+size-1; ++i, itr++ )
  }
  {
    out << "\nChecking itr+=1 and != ...\n";
    for( 
int i = 0; itr != ptr+
size; ++i, itr+=1 )
 
  }
  {
    out << "\nChecking itr=itr+1 and == ...\n";
    for( 
int i = 0; !( itr == ptr+
size ); ++i, itr=itr+1 )
 
  }
  
  {
    out << "\nChecking --itr and >= ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( 
int i = size-1; itr >= 
ptr; --i, --itr )
 
  }
  {
    out << "\nChecking itr-- and > ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( 
int i = size-1; itr+1 > 
ptr; i--, itr-- )
 
  }
  {
    out << "\nChecking itr-=1 and != ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( 
int i = size-1; itr+1 != 
ptr; i--, itr-=1 )
 
  }
  {
    out << "\nChecking itr=itr-1 and == ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( 
int i = size-1; !( itr+1 == 
ptr ); i--, itr=itr-1 )
 
  }
  
  {
    out << "\nChecking ptr.end() - ptr.begin() == ptr.size() ...\n";
  }
  
  {
    out << "\nChecking iterator ++itr and < ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr < ptr.end(); ++i, ++itr )
  }
  {
    out << "\nChecking iterator itr++ and <= ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr <= ptr.end()-1; ++i, itr++ )
  }
  {
    out << "\nChecking iterator itr+=1 and != ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr != ptr.end(); ++i, itr+=1 )
  }
  {
    out << "\nChecking iterator itr=itr+1 and == ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; !( itr == ptr.end() ); ++i, itr=itr+1 )
  }
  
  {
    out << "\nChecking iterator --itr and >= ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr >= ptr.begin(); --i, --itr )
  }
  {
    out << "\nChecking iterator itr-- and > ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr+1 > ptr.begin(); i--, itr-- )
  }
  {
    out << "\nChecking iterator itr-=1 and != ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr+1 != ptr.begin(); i--, itr-=1 )
  }
  {
    out << "\nChecking iterator itr=itr-1 and == ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; !( itr+1 == ptr.begin() ); i--, itr=itr-1 )
  }
  return success;
}
template<class T>
bool test_ArrayRCP(
  )
{
  using Teuchos::arcp;
  using Teuchos::arcp_const_cast;
  bool success = true, result;
  out
    << "\n***"
    << "\n*** Testing ptr = " << ptr
    << "\n***\n";
  const int n = ptr.size();
  {
    out << "\nInitializing data ...\n";
    for( int i = 0; i < n; ++i )
      ptr[i] = i;
  }
  result = test_ArrayRCP_iterators(ptr,out);
  if (!result) success = false;
  
  out << "\nTest const casting ...\n";
  
  {
    const ArrayRCP<const T> cptr2 = 
ptr;
 
  }
  
  out << "\nTest views ...\n";
  
  {
    out << "\nTest full non-const subview ...\n";
    const ArrayView<T> av2 = 
ptr(0,n);
 
  }
  {
    out << "\nTest full shorthand non-const subview ...\n";
    const ArrayView<T> av2 = 
ptr();
 
  }
  {
    out << "\nTest full const subview ...\n";
    const ArrayView<const T> cav2 = ptr.getConst()(0,n);
  }
  {
    out << "\nTest full non-const to const subview ...\n";
    const ArrayView<const T> cav2 = 
ptr(0,n);
 
  }
  {
    out << "\nTest full short-hand const subview ...\n";
    const ArrayView<const T> cav2 = ptr.getConst()();
  }
  {
    out << "\nTest implicit conversion from ArrayRCP<T> to ArrayView<T> ...\n";
    const ArrayView<T> av2 = 
ptr();
 
  }
  {
    out << "\nTest implicit conversion from ArrayRCP<const T> to ArrayView<const T> ...\n";
    const ArrayView<const T> av2 = ptr.getConst()();
  }
  {
    out << "\nTest almost implicit conversion from ArrayRCP<T> to ArrayView<const T> ...\n";
    const ArrayView<const T> av2 = 
ptr();
 
  }
  {
    out << "\nTest implicit conversion from ArrayRCP<T> to ArrayRCP<const T> ...\n";
    const ArrayRCP<const T> ptr2 = 
ptr;
 
  }
  {
    out << "\nTest clone of ArrayView<T> to ArrayRCP<T> ...\n";
    const ArrayRCP<T> ptr2 = Teuchos::arcpClone<T>(
ptr());
 
  }
  {
    out << "\nTest clone of ArrayPtr<const T> to ArrayRCP<T> ...\n";
    const ArrayRCP<T> ptr2 = Teuchos::arcpClone<T>(ptr.getConst()());
  }
  {
    out << "\nTest extra data ...\n";
    ArrayRCP<T> ptr2 = arcp<T>(n);
    Teuchos::set_extra_data( as<int>(1), "int", Teuchos::inOutArg(ptr2) );
  }
  return success;
}
int main( int argc, char* argv[] )
{
  using Teuchos::null;
  using Teuchos::arcp;
  using Teuchos::arcp_reinterpret_cast;
  
  bool success = true, result;
  try {
    
    int num_ints = 10;
    int num_doubles = 10;
    CommandLineProcessor clp(false); 
    clp.setOption( "num-ints", &num_ints, "Number of ints to allocate space for" );
    clp.setOption( "num-doubles", &num_doubles, "Number of doubles to allocate space for" );
    CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
    if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
      *out << "\nEnd Result: TEST FAILED" << std::endl;
      return parse_return;
    }
    const int sizeOfDouble = sizeof(double);
    const int sizeOfInt = sizeof(int);
    const int total_bytes = num_doubles*sizeOfDouble + num_ints*sizeOfInt;
    *out << std::endl << Teuchos::Teuchos_Version() << std::endl;
    *out << "\nTesting basic ArrayRCP functionality ...\n";
    ArrayRCP<char>
      char_ptr1 = arcp<char>(total_bytes);
    *out << "\nchar_ptr1 = " << char_ptr1 << "\n";
    result = test_ArrayRCP(char_ptr1,*out);
    if (!result) success = false;
    ArrayRCP<char>
      char_ptr2 = null;
    *out << "\nchar_ptr2 = " << char_ptr2 << "\n";
    ArrayRCP<char>
      char_ptr2b(char_ptr1); 
    *out << "\nchar_ptr2b = " << char_ptr2b << "\n";
    result = test_ArrayRCP(char_ptr2b,*out);
    if (!result) success = false;
    char_ptr2b = null;
    ArrayRCP<char>
      char_ptr3 = char_ptr1.persistingView(total_bytes/2,total_bytes/2);
    result = test_ArrayRCP(char_ptr3,*out);
    if (!result) success = false;
    *out << "\nchar_ptr3 = " << char_ptr3 << "\n";
    *out << "\nBreak up char_ptr1 into views of double and int data\n";
    int offset = 0;
      char_ptr1.persistingView(offset,sizeOfDouble*num_doubles)
      );
    *out << "\ndouble_ptr1 = " << double_ptr1 << "\n";
    result = test_ArrayRCP(double_ptr1,*out);
    if (!result) success = false;
    offset += sizeOfDouble*num_doubles;
      char_ptr1.persistingView(offset,sizeOfInt*num_ints)
      );
    *out << "\nint_ptr1 = " << int_ptr1 << "\n";
    result = test_ArrayRCP(int_ptr1,*out);
    if (!result) success = false;
    *out << "\nCreating a constant view of double_ptr1\n";
    ArrayRCP<const double>
    result = test_ArrayRCP_iterators(double_ptr2,*out);
    if (!result) success = false;
#ifdef SHOW_COMPILE_FAILURE_1
    
    
    
    for( int i = 0; i < double_ptr2.size(); ++i ) {
      double_ptr2[i] = 1.0; 
    }
#endif
    *out << "\nCreating an array of RCP objects!\n";
    ArrayRCP<RCP<double> >
      rcp_ptr1 = arcp<RCP<double> >(num_doubles);
    for( int i = 0; i < num_doubles; ++i )
      rcp_ptr1[i] = 
rcp(
new double(i));
 
    result = test_ArrayRCP_iterators(rcp_ptr1,*out);
    if (!result) success = false;
    *out << "\nCreating a const view of rcp_ptr1\n";
    ArrayRCP<const RCP<double> >
    result = test_ArrayRCP_iterators(rcp_ptr2,*out);
    if (!result) success = false;
    *out << "\nCreating an ARCP<double*> object doubleptr_ptr1 and dynamically allocation each element\n";
    ArrayRCP<double*>
      doubleptr_ptr1 = arcp<double*>(total_bytes);
    for( int i = 0; i < doubleptr_ptr1.size(); ++i )
      doubleptr_ptr1[i] = new double(i);
    result = test_ArrayRCP_iterators(doubleptr_ptr1,*out);
    if (!result) success = false;
    *out << "\nCreating an ARCP<double*const> view of a doubleptr_ptr1\n";
    ArrayRCP<double*const>
      doubleptr_ptr2 = doubleptr_ptr1.
getConst();
 
    result = test_ArrayRCP_iterators(doubleptr_ptr2,*out);
    if (!result) success = false;
#ifdef SHOW_COMPILE_FAILURE_2
    
    
    
    for( int i = 0; i < doubleptr_ptr2.size(); ++i ) {
      *doubleptr_ptr2[i] = 1.0; 
      doubleptr_ptr2[i] = NULL; 
    }
#endif
    *out << "\nCreating an ARCP<const double * const> view of a doubleptr_ptr1\n";
    ArrayRCP<const double*const>
      doubleptr_ptr3 = Teuchos::arcp_implicit_cast<const double*const>(doubleptr_ptr1);
    result = test_ArrayRCP_iterators(doubleptr_ptr3,*out);
    if (!result) success = false;
#ifdef SHOW_COMPILE_FAILURE_3
    
    
    
    for( int i = 0; i < doubleptr_ptr3.size(); ++i ) {
      *doubleptr_ptr3[i] = 1.0; 
      doubleptr_ptr3[i] = NULL; 
    }
#endif
    for( int i = 0; i < doubleptr_ptr1.size(); ++i )
      delete doubleptr_ptr1[i];
    *out << "\nWrapping RCP<std::vector<T> > objects as ArrayRCP objects ...\n";
    {
      ArrayRCP<char>
        vchar_ptr1 = 
arcp(
rcp(
new std::vector<char>(total_bytes)));
 
      *out << "\nvchar_ptr1 = " << vchar_ptr1 << "\n";
      result = test_ArrayRCP(vchar_ptr1,*out);
      if (!result) success = false;
      ArrayRCP<const char> vchar_ptr2 = vchar_ptr1;
      *out << "\nvchar_ptr2 = " << vchar_ptr2 << "\n";
      result = test_ArrayRCP_iterators(vchar_ptr2, *out);
      if (!result) success = false;
#ifndef __sun
      
      
      
#endif
    }
    *out << "\nWrapping RCP<ARray<T> > objects as ArrayRCP objects ...\n";
    {
      ArrayRCP<char>
      *out << "\nvchar_ptr1 = " << vchar_ptr1 << "\n";
      result = test_ArrayRCP(vchar_ptr1,*out);
      if (!result) success = false;
    }
    
    *out << "\nAll tests for ArrayRCP seem to check out!\n";
  }
  if(success)
    *out << "\nEnd Result: TEST PASSED" << std::endl; 
  return ( success ? 0 : 1 );
}