#include <boost/python.hpp>
#include "iostream"
#include "string"
#include "boost/weak_ptr.hpp"

using namespace boost::python;
using namespace std;
//using Teuchos::RCP;

struct I {
  virtual int foo() = 0;

  virtual ~I() {
    std::cout << "destructor for I called ..." << std::endl;
  }


  void setThisRCP(boost::shared_ptr<I> ptr) {
    thisRCP = ptr;
  }

  boost::shared_ptr<I> getThisRCP() const {
    return thisRCP.lock();
  }

  boost::weak_ptr<I> thisRCP;
};


struct IWrapper : public I, public boost::python::wrapper<I> {

  IWrapper() {

  }

  virtual int foo() {
    if( override f = this->get_override("foo") ) {
      return f();
    } else {
      return base_foo();
    }
  }


  int base_foo() {
    return 0; 
  }
};

struct J {
  virtual int foo() = 0;

  virtual ~J() {
    std::cout << "destructor for J called ..." << std::endl;
  }

  void setThisRCP(boost::shared_ptr<J> ptr) {
    thisRCP = ptr;
  }

  boost::shared_ptr<J> getThisRCP() const {
    return thisRCP.lock();
  }

  boost::weak_ptr<J> thisRCP;
};


struct JDer : public J {
  virtual int foo() {
    return 42;
  }
  
  static boost::shared_ptr<JDer> create() {
    boost::shared_ptr<JDer> ret(new JDer());
    ret->setThisRCP(ret);
    return ret;
  }

private:
  JDer() {

  }
};


BOOST_PYTHON_MODULE(thisRCPPy) 
{
  {
    typedef I ClassT;
    class_<IWrapper, boost::noncopyable >("I", init<>() )
      .def("setThisRCP", &ClassT::setThisRCP)
      .def("getThisRCP", &ClassT::getThisRCP)
      .def("foo", &ClassT::foo)
      ;
  }

  {
    typedef J ClassT;
    class_<ClassT, boost::shared_ptr<ClassT>, boost::noncopyable >("J", no_init )
      .def("setThisRCP", &ClassT::setThisRCP)
      .def("getThisRCP", &ClassT::getThisRCP)
      .def("foo", &ClassT::foo)
      ;
  }
  {
    typedef JDer ClassT;
    class_<ClassT, boost::shared_ptr<ClassT>, bases<J>, boost::noncopyable >("JDer", no_init )
      .def("__init__", make_constructor(&ClassT::create) )
      ;
  }
}
