
import os
import sys
import re
from pyplusplus import module_builder
from pyplusplus.module_builder.call_policies import *
from pyplusplus import function_transformers as FT


def generate_test_source():
    mb = module_builder.module_builder_t(files = ['test.h']
           , gccxml_path='C:/Program Files/gccxml_sherm/bin/gccxml.exe'
           , include_paths=['.', 'C:/Python26/include']
           , define_symbols=["_HAS_TR1=0"]
         )
    wrap_fn(mb)
    wrap_mbfnb(mb)

    mb.build_code_creator(module_name='_test')
    mb.write_module('wrap_test.cpp')

def wrap_fn(mb):
    fnw = mb.class_('fn_t_wrap')
    fnw.exclude()
    fn = mb.class_('fn_t')
    fn.no_init = True
    fn.held_type = 'std::auto_ptr< %s >' % fn.wrapper_alias
    fn_ptr_type = 'std::auto_ptr< %s >' % fn.decl_string
    fn1 = fn.class_('fn1_t')
    fn1.held_type = 'std::auto_ptr< %s::%s >' % (fn.wrapper_alias, fn1.wrapper_alias)
    fn1_ptr_type = 'std::auto_ptr< %s >' % fn1.decl_string
    fn1.add_registration_code(
        'bp::implicitly_convertible< %s, %s >();' % (fn1.held_type, fn_ptr_type), # parent
        works_on_instance=False)
    
def wrap_mbfnb(mb):
    fnb = mb.class_('mbfnb_t')
    fnb.constructors().exclude()
    # Create wrapped constructor to handle transfer of one raw pointer (this is a solved problem)
    fnb.add_declaration_code("""//
        static boost::shared_ptr< mbfnb_t > constructMbfnb1( std::auto_ptr<fn_t> ptr ) {
            return boost::shared_ptr< mbfnb_t >(new mbfnb_t(ptr.release()));
        }""")
    fnb.add_registration_code('def("__init__", bp::make_constructor(constructMbfnb1))')
    # Create wrapped constructor to handle vector of raw pointers (newly solved problem)
    fnb.add_declaration_code("#include <boost/python/stl_iterator.hpp>")
    fnb.add_declaration_code("""//
        static boost::shared_ptr< mbfnb_t > constructMbfnb2(bp::object list_of_fns) 
        {
            bp::stl_input_iterator< std::auto_ptr<fn_t> > begin(list_of_fns), end, i;
            std::vector<fn_t const *> ptrs;
            for (i = begin; i != end; ++i)
                // Odd. "i->release()" won't compile, but "(*i).release()" will...
                ptrs.push_back((*i).release());
            return boost::shared_ptr< mbfnb_t >(new mbfnb_t(ptrs));
        }""")
    fnb.add_registration_code('def("__init__", bp::make_constructor(constructMbfnb2))', tail=False)

if __name__ == "__main__":
    generate_test_source()

